V0.3.0 erldoc (#7)

* Adjusting version

* Initiating some edoc stuff

* Doc check

* Fixing docs

* Do a hard type check when entering nodes

* Two fixes:

- Module call change from enacl to ecu_eddsa
- Fix the v3 call endpoint for top block

* Fix top_block typespec and make top_height great again

* Fix typo
This commit is contained in:
Craig Everett
2023-09-04 22:20:01 +09:00
committed by GitHub
parent 1cd3c2c042
commit c2689903cd
7 changed files with 216 additions and 63 deletions
+77
View File
@@ -0,0 +1,77 @@
@author Craig Everett <ceverett@zxq9.com> [https://gitlab.com/zxq9/zj]
@version 0.3.0
@title Vanillae: Aeternity blockchain bindings for Erlang
@doc
This Erlang application provides bindings for the Erlang blockchain.
The primary goal is for usage to be easy to understand and as simple as possible to use.
The secondary goal is to enable real-world projects to more easily connect with the blockchain in an obvious way and provide a clear path for them to provide feedback regarding areas that are difficult to understand, functionality that is lacking, and explain their use cases to us so we can more easily provide needed features and usage examples to make adoption easier.
== Basic operation ==
All external interfaces expected to be used by authors of programs that use Vanillae are built into the `vanillae' module.
When Vanillae is started as an application a named process called `vanillae_man' is spawned that manages interactions with and the state of the service, as well as a simple-one-for-one supervisor that manages the lifecycle of Vanillae workers (defined in `vanillae_fetcher').
After startup `vanillae_man' must be given the address and port of a list of Aeternity nodes that are available to service requests. Note that the service nodes will need to have the "dry run" endpoint enabled and the internal service query port made available in order to provide "dry run" and mempool TX submission functionality.
The `vanillae_man' will round-robin requests to however many Aeternity nodes are provided in its configuration. Note that this congiruation is dynamic and can be changed completely at runtime.
== Functions ==
The `vanillae' module exposes one function per blockchain feature provided. Most of these are actually wrappers for blockchain endpoint functions, others provide functionality specific to accomplishing a local processing task related to chain data.
== Initialization ==
When Vanillae is first started the vanillae_man is started but does not yet know what Aeternity nodes to use to service queries. You will need to provide it with at least one node and port where it can make Aeternity endpoint calls.
Note that if you will need to make read-only calls to contracts that are deployed on chain (to queery their state or perform specific read-only operations provided by the contract) the backend nodes you configure will need to be configured with "dry-run" enabled.
Example of a shell session where vanillae is started and initialized manually with an AE node in the local network at 192.168.10.10:3013:
```
1> vanillae:start().
Starting.
ok
2> vanillae:status().
{error,no_nodes}
3> vanillae:ae_nodes([{"192.168.7.7", 3013}]).
ok
4> vanillae:status().
{ok,#{"difficulty" => 59729882,
"genesis_key_block_hash" =>
"kh_wUCideEB8aDtUaiHCtKcfywU6oHZW6gnyci8Mw6S1RSTCnCRu",
"listening" => true,"network_id" => "ae_uat",
"node_revision" =>
"3a08153c635c53d92029a617f2e784731ba367c6",
"node_version" => "6.7.0",
"peer_connections" => #{"inbound" => 25,"outbound" => 10},
"peer_count" => 50,
"peer_pubkey" =>
"pp_fCBqobeSwhdnrzC8DoSsmWbf2GzDK61CJujmsCEd3RUkmh9Ny",
"pending_transactions_count" => 2,
"protocols" =>
[#{"effective_at_height" => 425900,"version" => 5},
#{"effective_at_height" => 154300,"version" => 4},
#{"effective_at_height" => 82900,"version" => 3},
#{"effective_at_height" => 40900,"version" => 2},
#{"effective_at_height" => 0,"version" => 1}],
"solutions" => 0,"sync_progress" => 100.0,
"syncing" => false,"top_block_height" => 802644,
"top_key_block_hash" =>
"kh_28LZSvHZPCGqeWsMsqtSjxQjQHKW1pHzoBex97oMT7U2HcLPgV"}}
'''
Alternatively, here is a start function for an application using Vanillae that initializes vanillae_man with a list of nodes provided by a configuration file:
```
start(normal, _Args) ->
ok = application:ensure_started(sasl),
{ok, Started} = application:ensure_all_started(cowboy),
ok = application:ensure_started(vanillae),
Nodes = proplists:get_value(ae_nodes, read_config(), []),
ok = vanillae:ae_nodes(Nodes),
ok = log(info, "Started: ~p~n", [[vanillae | Started]]),
Routes = [{'_', [{"/", count_top, []}]}],
Dispatch = cowboy_router:compile(Routes),
Env = #{env => #{dispatch => Dispatch}},
{ok, _} = cowboy:start_clear(count_listener, [{port, 8080}], Env),
count_sup:start_link().
'''
+1 -1
View File
@@ -3,6 +3,6 @@
{registered,[]},
{included_applications,[]},
{applications,[stdlib,kernel]},
{vsn,"0.2.0"},
{vsn,"0.3.1"},
{modules,[vanillae,vanillae_fetcher,vanillae_man,vanillae_sup]},
{mod,{vanillae,[]}}]}.
+130 -56
View File
@@ -26,8 +26,8 @@
%%% @end
-module(vanillae).
-vsn("0.2.0").
%-behavior(application).
-vsn("0.3.1").
-behavior(application).
-author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>").
-license("GPL-3.0-or-later").
@@ -105,16 +105,21 @@
-type keyblock_hash() :: string(). % "kh_" ++ _
-type contract_byte_array() :: string(). % "cb_" ++ _
-type microblock_hash() :: string(). % "mh_" ++ _
%-type block_state_hash() :: string(). % "bs_" ++ _
%-type proof_of_fraud_hash() :: string() | no_fraud. % "bf_" ++ _
%-type signature() :: string(). % "sg_" ++ _
%-type block_tx_hash() :: string(). % "bx_" ++ _
-type tx_hash() :: string(). % "th_" ++ _
%-type name_hash() :: string(). % "nm_" ++ _
%-type protocol_info() :: #{string() => term()}.
% #{"effective_at_height" => non_neg_integer(),
% "version" => pos_integer()}.
-type keyblock() :: #{string() => term()}.
% <pre>
% #{"beneficiary" => account_id(),
% "hash" => keyblock_hash(),
% "height" => pos_integer(),
@@ -128,7 +133,9 @@
% "target" => non_neg_integer(),
% "time" => non_neg_integer(),
% "version" => 5}.
% </pre>
-type microblock_header() :: #{string() => term()}.
% <pre>
% #{"hash" => microblock_hash(),
% "height" => pos_integer(),
% "pof_hash" => proof_of_fraud_hash(),
@@ -139,7 +146,9 @@
% "time" => non_neg_integer(),
% "txs_hash" => block_tx_hash(),
% "version" => 1}.
% </pre>
-type transaction() :: #{string() => term()}.
% <pre>
% #{"block_hash" => microblock_hash(),
% "block_height" => pos_integer(),
% "hash" => tx_hash(),
@@ -158,16 +167,22 @@
% "type" => string(),
% "version" => pos_integer(),
% "vm_version" => pos_integer()}}
% </pre>
-type generation() :: #{string() => term()}.
% <pre>
% #{"key_block" => keyblock(),
% "micro_blocks" => [microblock_hash()]}.
% </pre>
-type account() :: #{string() => term()}.
% <pre>
% #{"balance" => non_neg_integer(),
% "id" => account_id(),
% "kind" => "basic",
% "nonce" => pos_integer(),
% "payable" => true}.
% </pre>
-type contract_data() :: #{string() => term()}.
% <pre>
% #{"abi_version " => pos_integer(),
% "active" => boolean(),
% "deposit" => non_neg_integer(),
@@ -175,12 +190,16 @@
% "owner_id" => account_id() | contract_id(),
% "referrer_ids" => [],
% "vm_version" => pos_integer()}.
% </pre>
-type name_info() :: #{string() => term()}.
% <pre>
% #{"id" => name_hash(),
% "owner" => account_id(),
% "pointers" => [],
% "ttl" => non_neg_integer()}.
% </pre>
-type status() :: #{string() => term()}.
% <pre>
% #{"difficulty" => non_neg_integer(),
% "genesis_key_block_hash" => keyblock_hash(),
% "listening" => boolean(),
@@ -198,7 +217,7 @@
% "syncing" => boolean(),
% "top_block_height" => non_neg_integer(),
% "top_key_block_hash" => keyblock_hash()}.
% </pre>
@@ -246,7 +265,7 @@ ae_nodes() ->
%% this may need to expand depending on how much query load your application generates.
%% The Vanillae manager will load balance by round-robin distribution.
ae_nodes(List) ->
ae_nodes(List) when is_list(List) ->
vanillae_man:ae_nodes(List).
@@ -275,25 +294,29 @@ timeout(MS) ->
-spec top_height() -> {ok, Height} | {error, Reason}
when Height :: pos_integer(),
Reason :: ae_error().
%% @doc
%% Retrieve the current height of the chain.
%%
%% NOTE:
%% This will return the currently synced height, which may be different than the
%% actual current top of the entire chain if the node being queried is still syncing
%% (has not yet caught up with the chain).
top_height() ->
case top_block() of
{ok, #{"micro_block" := #{"height" := Height}}} -> {ok, Height};
{ok, #{"key_block" := #{"height" := Height}}} -> {ok, Height};
Error -> Error
{ok, #{"height" := Height}} -> {ok, Height};
Error -> Error
end.
-spec top_block() -> {ok, TopBlock} | {error, Reason}
when TopBlock :: #{Type := Block},
Type :: string(), % "key_block" | "micro_block"
Block :: keyblock() | microblock_header(),
when TopBlock :: microblock_header(),
Reason :: ae_error().
%% @doc
%% Returns the current block height as an integer.
top_block() ->
request("/v3/blocks/top").
request("/v3/headers/top").
-spec kb_current() -> {ok, CurrentBlock} | {error, Reason}
@@ -573,6 +596,9 @@ dry_run(TX) ->
Accounts :: [pubkey()],
Result :: term(), % FIXME
Reason :: term(). % FIXME
%% @doc
%% Execute a read-only transaction on the chain at the current height with the
%% supplied accounts.
dry_run(TX, Accounts) ->
case kb_current_hash() of
@@ -697,6 +723,8 @@ contract(ID) ->
when ID :: contract_id(),
Bytecode :: contract_byte_array(),
Reason :: ae_error() | string().
%% @doc
%% Retrieve the code of a contract as represented on chain.
contract_code(ID) ->
case request(["/v3/contracts/", ID, "/code"]) of
@@ -710,6 +738,8 @@ contract_code(ID) ->
when ID :: contract_id(),
Bytecode :: contract_byte_array(),
Reason :: ae_error() | string().
%% @doc
%% Retrieve the POI of a contract stored on chain.
contract_poi(ID) ->
request(["/v3/contracts/", ID, "/poi"]).
@@ -827,7 +857,7 @@ contract_create(CreatorID, Path, InitArgs) ->
-spec contract_create(CreatorID, Nonce,
Amount, Gas, GasPrice, Fee,
Path, InitArgs) -> Result
when CreatorID :: unicode:chardata(),
when CreatorID :: pubkey(),
Nonce :: pos_integer(),
Amount :: non_neg_integer(),
Gas :: pos_integer(),
@@ -850,7 +880,8 @@ contract_create(CreatorID, Path, InitArgs) ->
%% <b>CreatorID:</b>
%% This is the <em>public</em> key of the entity who will be posting the contract
%% to the chain.
%% The key must be encoded as a binary string prefixed with <<"ak_">>.
%% The key must be encoded as a string prefixed with `"ak_"' (or `<<"ak_">>' in the
%% case of a binary string, which is also acceptable).
%% The returned call will still need to be signed by the caller's <em>private</em>
%% key.
%% </li>
@@ -941,7 +972,7 @@ contract_create(CreatorID, Path, InitArgs) ->
%% according to the function's spec, and represented as strings (that is, an integer
%% argument of `10' must be cast to the textual representation `"10"').
%% </li>
%% '''
%% </ul>
%% As should be obvious from the above description, it is pretty helpful to have a
%% source copy of the contract you intend to call so that you can re-generate the ACI
%% if you do not already have a copy, and can check the spec of a function before
@@ -1150,7 +1181,8 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
%% <li>
%% <b>CallerID:</b>
%% This is the <em>public</em> key of the entity making the contract call.
%% The key must be encoded as a binary string prefixed with <<"ak_">>.
%% The key must be encoded as a string prefixed with `"ak_"' (or `<<"ak_">>' in the
%% case of a binary string, which is also acceptable).
%% The returned call will still need to be signed by the caller's <em>private</em>
%% key.
%% </li>
@@ -1241,7 +1273,7 @@ contract_call(CallerID, Gas, AACI, ConID, Fun, Args) ->
%% according to the function's spec, and represented as strings (that is, an integer
%% argument of `10' must be cast to the textual representation `"10"').
%% </li>
%% '''
%% </ul>
%% As should be obvious from the above description, it is pretty helpful to have a
%% source copy of the contract you intend to call so that you can re-generate the ACI
%% if you do not already have a copy, and can check the spec of a function before
@@ -1335,7 +1367,8 @@ prepare_aaci(ACI) ->
Specs = simplify_specs(SpecDefs, #{}, Types),
{aaci, Name, Specs, Types}.
simplify_contract_types([], Types) -> Types;
simplify_contract_types([], Types) ->
Types;
simplify_contract_types([Next | Rest], Types) ->
TypeDefs = maps:get(typedefs, Next),
NameBin = maps:get(name, Next),
@@ -1351,7 +1384,8 @@ simplify_contract_types([Next | Rest], Types) ->
Types4 = simplify_typedefs(TypeDefs, Types3, Name ++ "."),
simplify_contract_types(Rest, Types4).
simplify_typedefs([], Types, _NamePrefix) -> Types;
simplify_typedefs([], Types, _NamePrefix) ->
Types;
simplify_typedefs([Next | Rest], Types, NamePrefix) ->
#{name := NameBin, vars := ParamDefs, typedef := T} = Next,
Name = NamePrefix ++ binary_to_list(NameBin),
@@ -1360,7 +1394,8 @@ simplify_typedefs([Next | Rest], Types, NamePrefix) ->
NewTypes = maps:put(Name, {Params, Type}, Types),
simplify_typedefs(Rest, NewTypes, NamePrefix).
simplify_specs([], Specs, _Types) -> Specs;
simplify_specs([], Specs, _Types) ->
Specs;
simplify_specs([Next | Rest], Specs, Types) ->
#{name := NameBin, arguments := ArgDefs, returns := ResultDef} = Next,
Name = binary_to_list(NameBin),
@@ -1444,9 +1479,9 @@ opaque_type_name(Name) -> binary_to_list(Name).
flatten_opaque_type(T, Types) ->
case normalize_opaque_type(T, Types) of
{ok, AlreadyNormalized, NOpaque, NExpanded} ->
flatten_opaque_type2(T, AlreadyNormalized, NOpaque, NExpanded,
Types);
Error -> Error
flatten_opaque_type2(T, AlreadyNormalized, NOpaque, NExpanded, Types);
Error ->
Error
end.
flatten_opaque_type2(T, AlreadyNormalized, NOpaque, NExpanded, Types) ->
@@ -1456,13 +1491,14 @@ flatten_opaque_type2(T, AlreadyNormalized, NOpaque, NExpanded, Types) ->
true -> {ok, {T, already_normalized, Flat}};
false -> {ok, {T, NOpaque, Flat}}
end;
Error -> Error
Error ->
Error
end.
flatten_opaque_types([T | Rest], Types, Acc) ->
case flatten_opaque_type(T, Types) of
{ok, Type} -> flatten_opaque_types(Rest, Types, [Type | Acc]);
Error -> Error
Error -> Error
end;
flatten_opaque_types([], _Types, Acc) ->
{ok, lists:reverse(Acc)}.
@@ -1470,16 +1506,15 @@ flatten_opaque_types([], _Types, Acc) ->
flatten_opaque_bindings([{Name, T} | Rest], Types, Acc) ->
case flatten_opaque_type(T, Types) of
{ok, Type} -> flatten_opaque_bindings(Rest, Types, [{Name, Type} | Acc]);
Error -> Error
Error -> Error
end;
flatten_opaque_bindings([], _Types, Acc) ->
{ok, lists:reverse(Acc)}.
flatten_opaque_variants([{Name, Elems} | Rest], Types, Acc) ->
case flatten_opaque_types(Elems, Types, []) of
{ok, ElemsFlat} ->
flatten_opaque_variants(Rest, Types, [{Name, ElemsFlat} | Acc]);
Error -> Error
{ok, ElemsFlat} -> flatten_opaque_variants(Rest, Types, [{Name, ElemsFlat} | Acc]);
Error -> Error
end;
flatten_opaque_variants([], _Types, Acc) ->
{ok, lists:reverse(Acc)}.
@@ -1489,23 +1524,23 @@ flatten_normalized_type(PrimitiveType, _Types) when is_atom(PrimitiveType) ->
flatten_normalized_type({variant, VariantsOpaque}, Types) ->
case flatten_opaque_variants(VariantsOpaque, Types, []) of
{ok, Variants} -> {ok, {variant, Variants}};
Error -> Error
Error -> Error
end;
flatten_normalized_type({record, FieldsOpaque}, Types) ->
case flatten_opaque_bindings(FieldsOpaque, Types, []) of
{ok, Fields} -> {ok, {record, Fields}};
Error -> Error
Error -> Error
end;
flatten_normalized_type({T, ElemsOpaque}, Types) ->
case flatten_opaque_types(ElemsOpaque, Types, []) of
{ok, Elems} -> {ok, {T, Elems}};
Error -> Error
Error -> Error
end.
normalize_opaque_type(T, Types) ->
case type_is_expanded(T) of
false -> normalize_opaque_type(T, Types, true);
true -> {ok, true, T, T}
true -> {ok, true, T, T}
end.
% FIXME detect infinite loops
@@ -1520,26 +1555,32 @@ normalize_opaque_type(T, Types, IsFirst) when is_list(T) ->
normalize_opaque_type({T, TypeArgs}, Types, IsFirst) when is_list(T) ->
case maps:find(T, Types) of
%{error, invalid_aci}; % FIXME more info
error -> {ok, IsFirst, {T, TypeArgs}, {unknown_type, TypeArgs}};
error ->
{ok, IsFirst, {T, TypeArgs}, {unknown_type, TypeArgs}};
{ok, {TypeParamNames, Definition}} ->
Bindings = lists:zip(TypeParamNames, TypeArgs),
normalize_opaque_type2(T, TypeArgs, Types, IsFirst, Bindings, Definition)
end.
normalize_opaque_type2(T, TypeArgs, Types, IsFirst, Bindings, Definition) ->
SubResult = case Bindings of
[] -> {ok, Definition};
_ -> substitute_opaque_type(Bindings, Definition)
end,
SubResult =
case Bindings of
[] -> {ok, Definition};
_ -> substitute_opaque_type(Bindings, Definition)
end,
case SubResult of
% Type names were already normalized if they were ADTs or records,
% since for those connectives the name is considered part of the type.
{ok, NextT = {variant, _}} -> {ok, IsFirst, {T, TypeArgs}, NextT};
{ok, NextT = {record, _}} -> {ok, IsFirst, {T, TypeArgs}, NextT};
{ok, NextT = {variant, _}} ->
{ok, IsFirst, {T, TypeArgs}, NextT};
{ok, NextT = {record, _}} ->
{ok, IsFirst, {T, TypeArgs}, NextT};
% Everything else has to be substituted down to a built-in connective
% to be considered normalized.
{ok, NextT} -> normalize_opaque_type3(NextT, Types);
Error -> Error
{ok, NextT} ->
normalize_opaque_type3(NextT, Types);
Error ->
Error
end.
% while this does look like normalize_opaque_type/2, it sets IsFirst to false
@@ -1548,34 +1589,34 @@ normalize_opaque_type2(T, TypeArgs, Types, IsFirst, Bindings, Definition) ->
normalize_opaque_type3(NextT, Types) ->
case type_is_expanded(NextT) of
false -> normalize_opaque_type(NextT, Types, false);
true -> {ok, false, NextT, NextT}
true -> {ok, false, NextT, NextT}
end.
% Strings indicate names that should be substituted. Atoms indicate built in
% types, which don't need to be expanded, except for option.
type_is_expanded({option, _}) -> false;
type_is_expanded(X) when is_atom(X) -> true;
type_is_expanded({option, _}) -> false;
type_is_expanded(X) when is_atom(X) -> true;
type_is_expanded({X, _}) when is_atom(X) -> true;
type_is_expanded(_) -> false.
type_is_expanded(_) -> false.
% Skip traversal if there is nothing to substitute. This will often be the
% most common case.
substitute_opaque_type(Bindings, {var, VarName}) ->
case lists:keyfind(VarName, 1, Bindings) of
false -> {error, invalid_aci};
false -> {error, invalid_aci};
{_, TypeArg} -> {ok, TypeArg}
end;
substitute_opaque_type(Bindings, {Connective, Args}) ->
case substitute_opaque_types(Bindings, Args, []) of
{ok, Result} -> {ok, {Connective, Result}};
Error -> Error
Error -> Error
end;
substitute_opaque_type(_Bindings, Type) -> {ok, Type}.
substitute_opaque_types(Bindings, [Next | Rest], Acc) ->
case substitute_opaque_type(Bindings, Next) of
{ok, Result} -> substitute_opaque_types(Bindings, Rest, [Result | Acc]);
Error -> Error
Error -> Error
end;
substitute_opaque_types(_Bindings, [], Acc) ->
{ok, lists:reverse(Acc)}.
@@ -1702,9 +1743,11 @@ coerce({O, N, {record, MemberTypes}}, {tuple, Tuple}, from_fate) ->
coerce({O, N, {unknown_type, _}}, Data, _) ->
case N of
already_normalized ->
io:format("Warning: Unknown type ~p. Using term ~p as is.~n", [O, Data]);
Message = "Warning: Unknown type ~p. Using term ~p as is.~n",
io:format(Message, [O, Data]);
_ ->
io:format("Warning: Unknown type ~p (i.e. ~p). Using term ~p as is.~n", [O, N, Data])
Message = "Warning: Unknown type ~p (i.e. ~p). Using term ~p as is.~n",
io:format(Message, [O, N, Data])
end,
{ok, Data};
coerce({O, N, _}, Data, from_fate) ->
@@ -1740,7 +1783,8 @@ coerce_map(KeyType, ValType, Remaining, Direction, Good, Broken) ->
case maps:next(Remaining) of
{K, V, RemainingAfter} ->
coerce_map2(KeyType, ValType, RemainingAfter, Direction, Good, Broken, K, V);
none -> coerce_map_finish(Good, Broken)
none ->
coerce_map_finish(Good, Broken)
end.
coerce_map2(KeyType, ValType, Remaining, Direction, Good, Broken, K, V) ->
@@ -1771,7 +1815,8 @@ coerce_map_finish(_, Broken) ->
lookup_variant(Name, Variants) -> lookup_variant(Name, Variants, 0).
lookup_variant(Name, [{Name, Terms} | _], Tag) -> {Tag, Terms};
lookup_variant(Name, [{Name, Terms} | _], Tag) ->
{Tag, Terms};
lookup_variant(Name, [_ | Rest], Tag) ->
lookup_variant(Name, Rest, Tag + 1);
lookup_variant(_Name, [], _Tag) ->
@@ -1823,7 +1868,8 @@ coerce_tuple_elements(Types, Terms, Direction, Tag) ->
coerce_tuple_elements([Type | Types], [Term | Terms], Direction, Tag, Index, Good, Broken) ->
case coerce(Type, Term, Direction) of
{ok, Value} -> coerce_tuple_elements(Types, Terms, Direction, Tag, Index + 1, [Value | Good], Broken);
{ok, Value} ->
coerce_tuple_elements(Types, Terms, Direction, Tag, Index + 1, [Value | Good], Broken);
{error, Errors} ->
Wrapped = wrap_errors({Tag, Index}, Errors),
coerce_tuple_elements(Types, Terms, Direction, Tag, Index + 1, Good, [Wrapped | Broken])
@@ -1843,7 +1889,8 @@ coerce_map_to_record(O, N, MemberTypes, Map) ->
case coerce_zipped_bindings(Zipped, to_fate, field) of
{ok, Converted} ->
{ok, {tuple, list_to_tuple(Converted)}};
Errors -> Errors
Errors ->
Errors
end;
{error, {missing_fields, Missing}} ->
single_error({missing_fields, O, N, Missing});
@@ -1866,7 +1913,8 @@ coerce_record_to_map(O, N, MemberTypes, Tuple) ->
single_error({record_too_few_terms, O, N, Tuple});
{error, too_many_terms} ->
single_error({record_too_many_terms, O, N, Tuple});
Errors -> Errors
Errors ->
Errors
end.
zip_record_fields(Fields, Map) ->
@@ -1961,6 +2009,21 @@ encode_call_data2(ArgDef, Fun, Args) ->
Errors -> Errors
end.
-spec verify_signature(Sig, Message, PubKey) -> Result
when Sig :: binary(),
Message :: iodata(),
PubKey :: pubkey(),
Result :: {ok, Outcome :: boolean()}
| {error, Reason :: term()}.
%% @doc
%% Verify a message signature given the signature, the message that was signed, and the
%% public half of the key that was used to sign.
%%
%% The result of a complete signature check is a boolean value return in an `{ok, Outcome}'
%% tuple, and any `{error, Reason}' return value is an indication that something about the
%% check failed before verification was able to pass or fail (bad key encoding or similar).
verify_signature(Sig, Message, PubKey) ->
case aeser_api_encoder:decode(PubKey) of
{account_pubkey, PK} -> verify_signature2(Sig, Message, PK);
@@ -1983,7 +2046,7 @@ verify_signature2(Sig, Message, PK) ->
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),
Result = ecu_eddsa:sign_verify_detached(Signature, Hashed, PK),
{ok, Result}.
@@ -2052,24 +2115,35 @@ eu(N, Size) ->
-spec start() -> ok | {error, Reason :: term()}.
%% @doc
%% Public function for manually starting the Vanillae application.
%%
%% NOTE:
%% To start it as a subordinate service within your own supervision tree rather than
%% as a peer Erlang application within your node, add the vanillae_sup to your own
%% supervision tree.
start() ->
application:start(vanillae).
-spec stop() -> ok | {error, Reason :: term()}.
%% @doc
%% Public function for manually stopping the Vanillae application.
stop() ->
application:stop(vanillae).
-spec start(normal, term()) -> {ok, pid()}.
%% @private
start(normal, _Args) ->
vanillae_sup:start_link().
-spec stop(term()) -> ok.
%% @private
stop(_State) ->
ok.
+3 -1
View File
@@ -1,5 +1,7 @@
%%% @private
-module(vanillae_fetcher).
-vsn("0.2.0").
-vsn("0.3.1").
-author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>").
-license("MIT").
+2 -2
View File
@@ -1,4 +1,4 @@
%%% @doc
%%% @private
%%% Vanillae Request Manager for Erlang
%%%
%%% This process is responsible for remembering the configured nodes and dispatching
@@ -9,7 +9,7 @@
%%% @end
-module(vanillae_man).
-vsn("0.2.0").
-vsn("0.3.1").
-behavior(gen_server).
-author("Craig Everett <ceverett@tsuriai.jp>").
-copyright("Craig Everett <ceverett@tsuriai.jp>").
+2 -2
View File
@@ -1,4 +1,4 @@
%%% @doc
%%% @private
%%% Vanillae Erlang Aeternity application supervisor
%%%
%%% The very top level supervisor in the system. It only has one service branch: the
@@ -9,7 +9,7 @@
%%% @end
-module(vanillae_sup).
-vsn("0.2.0").
-vsn("0.3.1").
-behaviour(supervisor).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
+1 -1
View File
@@ -14,7 +14,7 @@
{license,"MIT"}.
{modules,[]}.
{name,"Vanillae for Erlang"}.
{package_id,{"otpr","vanillae",{0,2,0}}}.
{package_id,{"otpr","vanillae",{0,3,1}}}.
{prefix,"v"}.
{repo_url,"https://github.com/aeternity/Vanillae"}.
{tags,[]}.