diff --git a/rebar.config b/rebar.config index d84c9d4..cee7ddb 100644 --- a/rebar.config +++ b/rebar.config @@ -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"}}} ]}. diff --git a/rebar.lock b/rebar.lock new file mode 100644 index 0000000..6e807c8 --- /dev/null +++ b/rebar.lock @@ -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}]. diff --git a/src/aeser_delegation.erl b/src/aeser_delegation.erl new file mode 100644 index 0000000..f399e66 --- /dev/null +++ b/src/aeser_delegation.erl @@ -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), + <>. + +assert_id(Type, AeserId) -> + Type = aeser_id:specialize_type(AeserId). diff --git a/test/aeser_delegation_tests.erl b/test/aeser_delegation_tests.erl new file mode 100644 index 0000000..6b88d79 --- /dev/null +++ b/test/aeser_delegation_tests.erl @@ -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} + ].