Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2488ff3978 | |||
| da8308821c | |||
| 213589ad9f | |||
| 270ebecc57 | |||
| 893ebb69f6 | |||
| 05c4f87619 | |||
| 91d6159ebd |
+1
-1
@@ -1,4 +1,4 @@
|
||||
{erl_opts, [debug_info]}.
|
||||
{deps, [ {base58, {git, "https://github.com/aeternity/erl-base58.git", {ref, "60a3356"}}}
|
||||
, {enacl, {git, "https://github.com/aeternity/enacl.git", {ref, "793ddb5"}}}
|
||||
, {enacl, {git, "https://github.com/aeternity/enacl.git", {ref, "67fceef"}}}
|
||||
]}.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[{<<"base58">>,
|
||||
{git,"https://github.com/aeternity/erl-base58.git",
|
||||
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
|
||||
0},
|
||||
{<<"enacl">>,
|
||||
{git,"https://github.com/aeternity/enacl.git",
|
||||
{ref,"67fceef42c0d055570f2e67b571f8d1f8de2f204"}},
|
||||
0}].
|
||||
@@ -30,6 +30,7 @@
|
||||
| oracle_query_id
|
||||
| oracle_response
|
||||
| account_pubkey
|
||||
| account_seckey
|
||||
| signature
|
||||
| name
|
||||
| commitment
|
||||
@@ -191,6 +192,7 @@ type2enc(oracle_query) -> ?BASE64;
|
||||
type2enc(oracle_query_id) -> ?BASE58;
|
||||
type2enc(oracle_response) -> ?BASE64;
|
||||
type2enc(account_pubkey) -> ?BASE58;
|
||||
type2enc(account_seckey) -> ?BASE58;
|
||||
type2enc(signature) -> ?BASE58;
|
||||
type2enc(commitment) -> ?BASE58;
|
||||
type2enc(peer_pubkey) -> ?BASE58;
|
||||
@@ -219,6 +221,7 @@ type2pfx(oracle_query) -> <<"ov">>;
|
||||
type2pfx(oracle_query_id) -> <<"oq">>;
|
||||
type2pfx(oracle_response) -> <<"or">>;
|
||||
type2pfx(account_pubkey) -> <<"ak">>;
|
||||
type2pfx(account_seckey) -> <<"sk">>;
|
||||
type2pfx(signature) -> <<"sg">>;
|
||||
type2pfx(commitment) -> <<"cm">>;
|
||||
type2pfx(peer_pubkey) -> <<"pp">>;
|
||||
@@ -246,6 +249,7 @@ pfx2type(<<"ov">>) -> oracle_query;
|
||||
pfx2type(<<"oq">>) -> oracle_query_id;
|
||||
pfx2type(<<"or">>) -> oracle_response;
|
||||
pfx2type(<<"ak">>) -> account_pubkey;
|
||||
pfx2type(<<"sk">>) -> account_seckey;
|
||||
pfx2type(<<"sg">>) -> signature;
|
||||
pfx2type(<<"cm">>) -> commitment;
|
||||
pfx2type(<<"pp">>) -> peer_pubkey;
|
||||
@@ -275,6 +279,7 @@ byte_size_for_type(oracle_query) -> not_applicable;
|
||||
byte_size_for_type(oracle_query_id) -> 32;
|
||||
byte_size_for_type(oracle_response) -> not_applicable;
|
||||
byte_size_for_type(account_pubkey) -> 32;
|
||||
byte_size_for_type(account_seckey) -> 32;
|
||||
byte_size_for_type(signature) -> 64;
|
||||
byte_size_for_type(name) -> not_applicable;
|
||||
byte_size_for_type(commitment) -> 32;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2023, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Serialization of delegation signatures
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeser_delegation).
|
||||
|
||||
-export([ aens_preclaim_sig/3
|
||||
, aens_name_sig/4
|
||||
, aens_sig/3
|
||||
|
||||
, oracle_sig/3
|
||||
, oracle_response_sig/3
|
||||
]).
|
||||
|
||||
%% Delegation signatures are prefixed with a unique tag, ensuring not to
|
||||
%% collide with serialized transactions.
|
||||
-define(DELEGATION_TAG, 16#1a01).
|
||||
|
||||
-define(TYPE_AENS, 1).
|
||||
-define(TYPE_AENS_NAME, 2).
|
||||
-define(TYPE_AENS_PRECLAIM, 3).
|
||||
-define(TYPE_ORACLE, 4).
|
||||
-define(TYPE_ORACLE_RESPONSE, 5).
|
||||
|
||||
-define(VSN, 1).
|
||||
|
||||
-type sig_data() :: binary().
|
||||
|
||||
-spec aens_preclaim_sig(binary(), aeser_id:id(), aeser_id:id()) -> sig_data().
|
||||
aens_preclaim_sig(NetworkId, Account, Contract) ->
|
||||
assert_id(account, Account),
|
||||
assert_id(contract, Contract),
|
||||
Template = [{account, id}, {contract, id}],
|
||||
Fields = [{account, Account}, {contract, Contract}],
|
||||
serialize(?TYPE_AENS_PRECLAIM, NetworkId, Template, Fields).
|
||||
|
||||
-spec aens_name_sig(binary(), aeser_id:id(), aeser_id:id(), aeser_id:id()) -> sig_data().
|
||||
aens_name_sig(NetworkId, Account, Name, Contract) ->
|
||||
assert_id(account, Account),
|
||||
assert_id(name, Name),
|
||||
assert_id(contract, Contract),
|
||||
Template = [{account, id}, {name, id}, {contract, id}],
|
||||
Fields = [{account, Account}, {name, Name}, {contract, Contract}],
|
||||
serialize(?TYPE_AENS_NAME, NetworkId, Template, Fields).
|
||||
|
||||
-spec aens_sig(binary(), aeser_id:id(), aeser_id:id()) -> sig_data().
|
||||
aens_sig(NetworkId, Account, Contract) ->
|
||||
assert_id(account, Account),
|
||||
assert_id(contract, Contract),
|
||||
Template = [{account, id}, {contract, id}],
|
||||
Fields = [{account, Account}, {contract, Contract}],
|
||||
serialize(?TYPE_AENS, NetworkId, Template, Fields).
|
||||
|
||||
-spec oracle_sig(binary(), aeser_id:id(), aeser_id:id()) -> sig_data().
|
||||
oracle_sig(NetworkId, Account, Contract) ->
|
||||
assert_id(account, Account),
|
||||
assert_id(contract, Contract),
|
||||
Template = [{account, id}, {contract, id}],
|
||||
Fields = [{account, Account}, {contract, Contract}],
|
||||
serialize(?TYPE_ORACLE, NetworkId, Template, Fields).
|
||||
|
||||
-spec oracle_response_sig(binary(), aeser_id:id(), aeser_id:id()) -> sig_data().
|
||||
oracle_response_sig(NetworkId, QueryId, Contract) ->
|
||||
assert_id(oracle, QueryId),
|
||||
assert_id(contract, Contract),
|
||||
Template = [{query, id}, {contract, id}],
|
||||
Fields = [{query, QueryId}, {contract, Contract}],
|
||||
serialize(?TYPE_ORACLE_RESPONSE, NetworkId, Template, Fields).
|
||||
|
||||
%% ------------------------------------------------------------------------
|
||||
%% -- Internal functions
|
||||
%% ------------------------------------------------------------------------
|
||||
|
||||
serialize(Type, NetworkId, Template, Fields) ->
|
||||
Data = aeserialization:serialize(Type, ?VSN, Template, Fields),
|
||||
<<?DELEGATION_TAG:16, NetworkId/binary, Data/binary>>.
|
||||
|
||||
assert_id(Type, AeserId) ->
|
||||
Type = aeser_id:specialize_type(AeserId).
|
||||
@@ -28,12 +28,14 @@
|
||||
| 'binary'
|
||||
| 'id' %% As defined in aec_id.erl
|
||||
| [type()] %% Length one in the type. This means a list of any length.
|
||||
| #{items := [{field_name(), type()}]} %% Record with named fields represented as a map. Encoded as a list in the given order.
|
||||
| tuple(). %% Any arity, containing type(). This means a static size array.
|
||||
|
||||
-type encodable_term() :: non_neg_integer()
|
||||
| binary()
|
||||
| boolean()
|
||||
| [encodable_term()] %% Of any length
|
||||
| #{atom() => encodable_term()}
|
||||
| tuple() %% Any arity, containing encodable_term().
|
||||
| aeser_id:id().
|
||||
|
||||
@@ -101,6 +103,12 @@ decode_fields(Template, Values) ->
|
||||
|
||||
encode_field([Type], L) when is_list(L) ->
|
||||
[encode_field(Type, X) || X <- L];
|
||||
encode_field(#{items := Items}, Map) ->
|
||||
lists:map(
|
||||
fun({K, Type}) ->
|
||||
V = maps:get(K, Map),
|
||||
encode_field(Type, V)
|
||||
end, Items);
|
||||
encode_field(Type, T) when tuple_size(Type) =:= tuple_size(T) ->
|
||||
Zipped = lists:zip(tuple_to_list(Type), tuple_to_list(T)),
|
||||
[encode_field(X, Y) || {X, Y} <- Zipped];
|
||||
@@ -117,6 +125,13 @@ encode_field(Type, Val) -> error({illegal, Type, Val}).
|
||||
|
||||
decode_field([Type], List) when is_list(List) ->
|
||||
[decode_field(Type, X) || X <- List];
|
||||
decode_field(#{items := Items}, List) when length(List) =:= length(Items) ->
|
||||
Zipped = lists:zip(Items, List),
|
||||
lists:foldl(
|
||||
fun({{K, Type}, V}, Map) ->
|
||||
maps:is_key(K, Map) andalso error(badarg, duplicate_field),
|
||||
Map#{ K => decode_field(Type, V) }
|
||||
end, #{}, Zipped);
|
||||
decode_field(Type, List) when length(List) =:= tuple_size(Type) ->
|
||||
Zipped = lists:zip(tuple_to_list(Type), List),
|
||||
list_to_tuple([decode_field(X, Y) || {X, Y} <- Zipped]);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @copyright (C) 2023, Aeternity Anstalt
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeser_delegation_tests).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-define(TEST_MODULE, aeser_delegation).
|
||||
|
||||
-define(ACCOUNT, aeser_id:create(account, <<1:256>>)).
|
||||
-define(CONTRACT, aeser_id:create(contract, <<2:256>>)).
|
||||
-define(NAME, aeser_id:create(name, <<3:256>>)).
|
||||
-define(ORACLE, aeser_id:create(oracle, <<3:256>>)).
|
||||
|
||||
-define(NETWORK_ID, <<"my_fancy_network"/utf8>>).
|
||||
|
||||
encode_correct_test_() ->
|
||||
[{"Encode preclaim sig",
|
||||
fun() ->
|
||||
aeser_delegation:aens_preclaim_sig(?NETWORK_ID, ?ACCOUNT, ?CONTRACT)
|
||||
end},
|
||||
{"Encode name sig",
|
||||
fun() ->
|
||||
aeser_delegation:aens_name_sig(?NETWORK_ID, ?ACCOUNT, ?NAME, ?CONTRACT)
|
||||
end},
|
||||
{"Encode aens wildcard sig",
|
||||
fun() ->
|
||||
aeser_delegation:aens_sig(?NETWORK_ID, ?ACCOUNT, ?CONTRACT)
|
||||
end},
|
||||
{"Encode oracle sig",
|
||||
fun() ->
|
||||
aeser_delegation:oracle_sig(?NETWORK_ID, ?ACCOUNT, ?CONTRACT)
|
||||
end},
|
||||
{"Encode oracle response sig",
|
||||
fun() ->
|
||||
aeser_delegation:oracle_response_sig(?NETWORK_ID, ?ORACLE, ?CONTRACT)
|
||||
end}
|
||||
].
|
||||
|
||||
encode_fail_test_() ->
|
||||
[{"Bad encoding preclaim sig",
|
||||
fun() ->
|
||||
?assertError(_, aeser_delegation:aens_preclaim_sig(?NETWORK_ID, <<42:256>>, ?CONTRACT)),
|
||||
?assertError(_, aeser_delegation:aens_preclaim_sig(?NETWORK_ID, ?CONTRACT, ?ACCOUNT))
|
||||
end},
|
||||
{"Bad encoding name sig",
|
||||
fun() ->
|
||||
?assertError(_, aeser_delegation:aens_name_sig(?NETWORK_ID, ?ACCOUNT, <<42:256>>, ?CONTRACT)),
|
||||
?assertError(_, aeser_delegation:aens_name_sig(?NETWORK_ID, ?NAME, ?ACCOUNT, ?CONTRACT))
|
||||
end},
|
||||
{"Bad encoding aens wildcard sig",
|
||||
fun() ->
|
||||
?assertError(_, aeser_delegation:aens_sig(?NETWORK_ID, ?ACCOUNT, <<42:256>>)),
|
||||
?assertError(_, aeser_delegation:aens_sig(?NETWORK_ID, ?CONTRACT, ?CONTRACT))
|
||||
end},
|
||||
{"Bad encoding oracle sig",
|
||||
fun() ->
|
||||
?assertError(_, aeser_delegation:oracle_sig(?NETWORK_ID, <<42:256>>, ?CONTRACT)),
|
||||
?assertError(_, aeser_delegation:oracle_sig(?NETWORK_ID, ?ACCOUNT, ?ACCOUNT))
|
||||
end},
|
||||
{"Bad encoding oracle response sig",
|
||||
fun() ->
|
||||
?assertError(_, aeser_delegation:oracle_response_sig(?NETWORK_ID, <<42:256>>, ?CONTRACT)),
|
||||
?assertError(_, aeser_delegation:oracle_response_sig(?NETWORK_ID, ?ORACLE, ?ORACLE))
|
||||
end}
|
||||
].
|
||||
Reference in New Issue
Block a user