Compare commits

..

4 Commits

Author SHA1 Message Date
Hans Svensson e2ce3a0414 Add rollup_tx and hash encoding 2024-03-08 14:19:33 +01:00
Hans Svensson 9d9026e760 More chain objects for associate chains 2024-03-05 20:54:58 +01:00
Hans Svensson b3105c466f Add chain object acs_mtree 2024-03-01 08:26:57 +01:00
Hans Svensson 4d2beb0337 Add id tag and serializations for associate chain 2024-02-29 14:32:36 +01:00
27 changed files with 237 additions and 1139 deletions
+37
View File
@@ -0,0 +1,37 @@
version: 2.1
executors:
aebuilder:
docker:
- image: aeternity/builder:bionic-otp23
user: builder
working_directory: ~/src
jobs:
build:
executor: aebuilder
steps:
- checkout
- restore_cache:
keys:
- dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }}
- dialyzer-cache-v1-{{ .Branch }}-
- dialyzer-cache-v1-
- run:
name: Build
command: rebar3 compile
- run:
name: Static Analysis
command: rebar3 dialyzer
- run:
name: Eunit
command: rebar3 eunit
- run:
name: Common Tests
command: rebar3 ct
- save_cache:
key: dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }}
paths:
- _build/default/rebar3_20.3.8_plt
- store_artifacts:
path: _build/test/logs
-14
View File
@@ -1,14 +0,0 @@
name: Gajumaru Serialization Tests
run-name: ${{ gitea.actor }} testing Gajumaru Serialization
on: [push, workflow_dispatch]
jobs:
tests:
runs-on: linux_amd64
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: eunit
run: |
. /home/act_runner/.erts/27.2.1/activate
./rebar3 eunit
+1 -1
View File
@@ -7,7 +7,7 @@ _*
*.swp
*.swo
.erlang.cookie
ebin/*.beam
ebin
log
erl_crash.dump
.rebar
-1
View File
@@ -1 +0,0 @@
{"src/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]}.
-1
View File
@@ -1,6 +1,5 @@
ISC License
Copyright (c) 2025, QPQ AG
Copyright (c) 2017, aeternity developers
Permission to use, copy, modify, and/or distribute this software for any
+5 -125
View File
@@ -1,129 +1,9 @@
# GM Serialization
aeserialization
=====
Serialization helpers for the Gajumaru.
Serialization helpers for Aeternity node.
## Build
Build
-----
$ rebar3 compile
## Test
$ rebar3 eunit
## Dynamic encoding
The module `gmser_dyn` offers dynamic encoding support, encoding most 'regular'
Erlang data types into an internal RLP representation.
Main API:
* `encode(term()) -> iolist()`
* `encode_typed(template(), term()) -> iolist()`
* `decode(iolist()) -> term()`
* `serialize(term()) -> binary()`
* `serialize_typed(template(), term()) -> binary()`
* `deserialize(binary()) -> term()`
In the examples below, we use the `decode` functions, to illustrate
how the type information is represented. The fully serialized form is
produced by the `serialize` functions.
The basic types supported by the encoder are:
* `neg_integer()` (`negint`, code: 247)
* `non_neg_integer()` (`int` , code: 248)
* `binary()` (`binary`, code: 249)
* `boolean()` (`bool` , code: 250)
* `list()` (`list` , code: 251)
* `map()` (`map` , code: 252)
* `tuple()` (`tuple` , code: 253)
* `gmser_id:id()` (`id` , code: 254)
* `atom()` (`label` , code: 255)
When encoding `map` types, the map elements are first sorted.
When specifying a map type for template-driven encoding, use
the `#{items => [{Key, Value}]}` construct.
## Labels
Labels correspond to (existing) atoms in Erlang.
Decoding of a label results in a call to `binary_to_existing_atom/2`, so will
fail if the corresponding atom does not already exist.
It's possible to cache labels for more compact encoding.
Note that when caching labels, the same cache mapping needs to be used on the
decoder side.
Labels are encoded as `[<<255>>, << AtomToBinary/binary >>]`.
If a cached label is used, the encoding becomes `[<<255>, [Ix]]`, where
`Ix` is the integer-encoded index value of the cached label.
## Examples
Dynamically encoded objects have the basic structure `[<<0>>,V,Obj]`, where `V` is the
integer-coded version, and `Obj` is the top-level encoding on the form `[Tag,Data]`.
```erlang
E = fun(T) -> io:fwrite("~w~n", [gmser_dyn:encode(T)]) end.
E(17) -> [<<0>>,<<1>>,[<<248>>,<<17>>]]
E(<<"abc">>) -> [<<0>>,<<1>>,[<<249>>,<<97,98,99>>]]
E(true) -> [<<0>>,<<1>>,[<<250>>,<<1>>]]
E(false) -> [<<0>>,<<1>>,[<<250>>,<<0>>]]
E([1,2]) -> [<<0>>,<<1>>,[<<251>>,[[<<248>>,<<1>>],[<<248>>,<<2>>]]]]
E({1,2}) -> [<<0>>,<<1>>,[<<253>>,[[<<248>>,<<1>>],[<<248>>,<<2>>]]]]
E(#{a=>1, b=>2}) ->
[<<0>>,<<1>>,[<<252>>,[[[<<255>>,<<97>>],[<<248>>,<<1>>]],[[<<255>>,<<98>>],[<<248>>,<<2>>]]]]]
E(gmser_id:create(account,<<1:256>>)) ->
[<<0>>,<<1>>,[<<254>>,<<1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>]]
```
Note that tuples and list are encoded the same way, except for the initial type tag.
Maps are encoded as `[<Map>, [KV1, KV2, ...]]`, where `[KV1, KV2, ...]` is the sorted
list of key-value tuples from `map:to_list(Map)`, but with the `tuple` type tag omitted.
## Template-driven encoding
Templates can be provided to the encoder by either naming an already registered
type, or by passing a template directly. In both cases, the encoder will enforce
the type information in the template.
If the template has been registered, the encoder omits inner type tags (still
inserting the top-level tag), leading to some compression of the output.
This also means that the serialized term cannot be decoded without the same
schema information on the decoder side.
In the case of a directly provided template, all type information is inserted,
such that the serialized term can be decoded without any added type information.
The template types are still enforced during encoding.
```erlang
ET = fun(Type,Term) -> io:fwrite("~w~n", [gmser_dyn:encode_typed(Type,Term)]) end.
ET([{int,int}], [{1,2}]) -> [<<0>>,<<1>>,[<<251>>,[[[<<248>>,<<1>>],[<<248>>,<<2>>]]]]]
gmser_dyn:register_type(1000,lt2i,[{int,int}]).
ET(lt2i, [{1,2}]) -> [<<0>>,<<1>>,[<<3,232>>,[[<<1>>,<<2>>]]]]
```
### Alternative types
The dynamic encoder supports two additions to the `gmserialization` template
language: `any` and `#{alt => [AltTypes]}`.
The `any` type doesn't have an associated code, but enforces dynamic encoding.
The `#{alt => [Type]}` construct also enforces dynamic encoding, and will try
to encode as each type in the list, in the specified order, until one matches.
```erlang
gmser_dyn:encode_typed(#{alt => [negint,int]}, 5) -> [<<0>>,<<1>>,[<<247>>,<<5>>]]
gmser_dyn:encode_typed(#{alt => [negint,int]}, 5) -> [<<0>>,<<1>>,[<<248>>,<<5>>]]
gmser_dyn:register_type(246, anyint, #{alt => [negint, int]})
gmser_dyn:encode_typed(anyint,-5) -> [<<0>>,<<1>>,[<<246>>,[<<247>>,<<5>>]]]
gmser_dyn:encode_typed(anyint,5) -> [<<0>>,<<1>>,[<<246>>,[<<248>>,<<5>>]]]
```
-11
View File
@@ -1,11 +0,0 @@
{application,gmserialization,
[{description,"Serialization of data for the Gajumaru"},
{vsn,"0.1.2"},
{registered,[]},
{applications,[kernel,stdlib,crypto,base58]},
{env,[]},
{modules,[gmser_api_encoder,gmser_chain_objects,
gmser_contract_code,gmser_delegation,gmser_id,
gmser_rlp,gmserialization]},
{licenses,[]},
{links,[]}]}.
+3 -9
View File
@@ -1,10 +1,4 @@
{erl_opts, [debug_info]}.
{deps,
[{base58,
{git,
"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
{ref, "e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}}},
{enacl,
{git,
"https://git.qpq.swiss/QPQ-AG/enacl.git",
{ref, "4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}}]}.
{deps, [ {base58, {git, "https://github.com/aeternity/erl-base58.git", {ref, "60a3356"}}}
, {enacl, {git, "https://github.com/aeternity/enacl.git", {ref, "67fceef"}}}
]}.
+4 -4
View File
@@ -1,8 +1,8 @@
[{<<"base58">>,
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
{git,"https://github.com/aeternity/erl-base58.git",
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
0},
{<<"enacl">>,
{git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
{git,"https://github.com/aeternity/enacl.git",
{ref,"67fceef42c0d055570f2e67b571f8d1f8de2f204"}},
0}].
BIN
View File
Binary file not shown.
@@ -1,12 +1,10 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% API encoding for the Gajumaru
%%% API encoding for the Aeternity node.
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_api_encoder).
-vsn("0.1.2").
-module(aeser_api_encoder).
-export([encode/2,
decode/1,
@@ -20,22 +18,22 @@
| block_pof_hash
| block_tx_hash
| block_state_hash
| block_witness_hash
| channel
| contract_bytearray
| contract_pubkey
| contract_store_key
| contract_store_value
| contract_source
| transaction
| tx_hash
| oracle_pubkey
| oracle_query
| oracle_query_id
| oracle_response
| account_pubkey
| account_seckey
| associate_chain
| entry
| signature
| name
| native_token
| commitment
| peer_pubkey
| state
@@ -54,9 +52,9 @@
-define(BASE58, 1).
-define(BASE64, 2).
-spec encode(known_type(), payload() | gmser_id:id()) -> encoded().
-spec encode(known_type(), payload() | aeser_id:id()) -> encoded().
encode(id_hash, Payload) ->
{IdType, Val} = gmser_id:specialize(Payload),
{IdType, Val} = aeser_id:specialize(Payload),
encode(id2type(IdType), Val);
encode(Type, Payload) ->
Pfx = type2pfx(Type),
@@ -92,14 +90,14 @@ type_size_check(Type, Bin) ->
end
end.
-spec safe_decode(extended_type(), encoded()) -> {'ok', payload() | gmser_id:id()}
-spec safe_decode(extended_type(), encoded()) -> {'ok', payload() | aeser_id:id()}
| {'error', atom()}.
safe_decode({id_hash, AllowedTypes}, Enc) ->
try decode(Enc) of
{ActualType, Dec} ->
case lists:member(ActualType, AllowedTypes) of
true ->
try {ok, gmser_id:create(type2id(ActualType), Dec)}
try {ok, aeser_id:create(type2id(ActualType), Dec)}
catch error:_ -> {error, invalid_prefix}
end;
false ->
@@ -170,35 +168,33 @@ id2type(associate_chain) -> associate_chain;
id2type(channel) -> channel;
id2type(commitment) -> commitment;
id2type(contract) -> contract_pubkey;
id2type(contract_source) -> contract_source;
id2type(name) -> name;
id2type(native_token) -> native_token;
id2type(entry) -> entry.
id2type(oracle) -> oracle_pubkey.
type2id(account_pubkey) -> account;
type2id(associate_chain) -> associate_chain;
type2id(channel) -> channel;
type2id(commitment) -> commitment;
type2id(contract_pubkey) -> contract;
type2id(contract_source) -> contract_source;
type2id(name) -> name;
type2id(native_token) -> native_token;
type2id(entry) -> entry.
type2id(oracle_pubkey) -> oracle.
type2enc(key_block_hash) -> ?BASE58;
type2enc(micro_block_hash) -> ?BASE58;
type2enc(block_pof_hash) -> ?BASE58;
type2enc(block_tx_hash) -> ?BASE58;
type2enc(block_state_hash) -> ?BASE58;
type2enc(block_witness_hash) -> ?BASE58;
type2enc(channel) -> ?BASE58;
type2enc(contract_pubkey) -> ?BASE58;
type2enc(contract_bytearray) -> ?BASE64;
type2enc(contract_store_key) -> ?BASE64;
type2enc(contract_store_value) -> ?BASE64;
type2enc(contract_source) -> ?BASE64;
type2enc(transaction) -> ?BASE64;
type2enc(tx_hash) -> ?BASE58;
type2enc(oracle_pubkey) -> ?BASE58;
type2enc(oracle_query) -> ?BASE64;
type2enc(oracle_query_id) -> ?BASE58;
type2enc(oracle_response) -> ?BASE64;
type2enc(account_pubkey) -> ?BASE58;
type2enc(account_seckey) -> ?BASE58;
type2enc(associate_chain) -> ?BASE58;
@@ -206,14 +202,12 @@ type2enc(signature) -> ?BASE58;
type2enc(commitment) -> ?BASE58;
type2enc(peer_pubkey) -> ?BASE58;
type2enc(name) -> ?BASE58;
type2enc(native_token) -> ?BASE58;
type2enc(state) -> ?BASE64;
type2enc(poi) -> ?BASE64;
type2enc(state_trees) -> ?BASE64;
type2enc(call_state_tree) -> ?BASE64;
type2enc(mp_tree_hash) -> ?BASE58;
type2enc(hash) -> ?BASE58;
type2enc(entry) -> ?BASE64;
type2enc(bytearray) -> ?BASE64.
@@ -222,15 +216,17 @@ type2pfx(micro_block_hash) -> <<"mh">>;
type2pfx(block_pof_hash) -> <<"bf">>;
type2pfx(block_tx_hash) -> <<"bx">>;
type2pfx(block_state_hash) -> <<"bs">>;
type2pfx(block_witness_hash) -> <<"ws">>;
type2pfx(channel) -> <<"ch">>;
type2pfx(contract_pubkey) -> <<"ct">>;
type2pfx(contract_bytearray) -> <<"cb">>;
type2pfx(contract_store_key) -> <<"ck">>;
type2pfx(contract_store_value) -> <<"cv">>;
type2pfx(contract_source) -> <<"cx">>;
type2pfx(transaction) -> <<"tx">>;
type2pfx(tx_hash) -> <<"th">>;
type2pfx(oracle_pubkey) -> <<"ok">>;
type2pfx(oracle_query) -> <<"ov">>;
type2pfx(oracle_query_id) -> <<"oq">>;
type2pfx(oracle_response) -> <<"or">>;
type2pfx(account_pubkey) -> <<"ak">>;
type2pfx(account_seckey) -> <<"sk">>;
type2pfx(associate_chain) -> <<"ac">>;
@@ -238,14 +234,12 @@ type2pfx(signature) -> <<"sg">>;
type2pfx(commitment) -> <<"cm">>;
type2pfx(peer_pubkey) -> <<"pp">>;
type2pfx(name) -> <<"nm">>;
type2pfx(native_token) -> <<"nt">>;
type2pfx(state) -> <<"st">>;
type2pfx(poi) -> <<"pi">>;
type2pfx(state_trees) -> <<"ss">>;
type2pfx(call_state_tree) -> <<"cs">>;
type2pfx(mp_tree_hash) -> <<"mt">>;
type2pfx(hash) -> <<"hs">>;
type2pfx(entry) -> <<"en">>;
type2pfx(bytearray) -> <<"ba">>.
pfx2type(<<"kh">>) -> key_block_hash;
@@ -253,15 +247,17 @@ pfx2type(<<"mh">>) -> micro_block_hash;
pfx2type(<<"bf">>) -> block_pof_hash;
pfx2type(<<"bx">>) -> block_tx_hash;
pfx2type(<<"bs">>) -> block_state_hash;
pfx2type(<<"ws">>) -> block_witness_hash;
pfx2type(<<"ch">>) -> channel;
pfx2type(<<"cb">>) -> contract_bytearray;
pfx2type(<<"ck">>) -> contract_store_key;
pfx2type(<<"cv">>) -> contract_store_value;
pfx2type(<<"ct">>) -> contract_pubkey;
pfx2type(<<"cx">>) -> contract_source;
pfx2type(<<"tx">>) -> transaction;
pfx2type(<<"th">>) -> tx_hash;
pfx2type(<<"ok">>) -> oracle_pubkey;
pfx2type(<<"ov">>) -> oracle_query;
pfx2type(<<"oq">>) -> oracle_query_id;
pfx2type(<<"or">>) -> oracle_response;
pfx2type(<<"ak">>) -> account_pubkey;
pfx2type(<<"sk">>) -> account_seckey;
pfx2type(<<"ac">>) -> associate_chain;
@@ -269,14 +265,12 @@ pfx2type(<<"sg">>) -> signature;
pfx2type(<<"cm">>) -> commitment;
pfx2type(<<"pp">>) -> peer_pubkey;
pfx2type(<<"nm">>) -> name;
pfx2type(<<"nt">>) -> native_token;
pfx2type(<<"st">>) -> state;
pfx2type(<<"pi">>) -> poi;
pfx2type(<<"ss">>) -> state_trees;
pfx2type(<<"cs">>) -> call_state_tree;
pfx2type(<<"mt">>) -> mp_tree_hash;
pfx2type(<<"hs">>) -> hash;
pfx2type(<<"en">>) -> entry;
pfx2type(<<"ba">>) -> bytearray.
-spec byte_size_for_type(known_type()) -> non_neg_integer() | not_applicable.
@@ -286,21 +280,22 @@ byte_size_for_type(micro_block_hash) -> 32;
byte_size_for_type(block_pof_hash) -> 32;
byte_size_for_type(block_tx_hash) -> 32;
byte_size_for_type(block_state_hash) -> 32;
byte_size_for_type(block_witness_hash) -> 32;
byte_size_for_type(channel) -> 32;
byte_size_for_type(contract_pubkey) -> 32;
byte_size_for_type(contract_bytearray) -> not_applicable;
byte_size_for_type(contract_store_key) -> not_applicable;
byte_size_for_type(contract_store_value) -> not_applicable;
byte_size_for_type(contract_source) -> not_applicable;
byte_size_for_type(transaction) -> not_applicable;
byte_size_for_type(tx_hash) -> 32;
byte_size_for_type(oracle_pubkey) -> 32;
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(associate_chain) -> 32;
byte_size_for_type(signature) -> 64;
byte_size_for_type(name) -> not_applicable;
byte_size_for_type(native_token) -> 32;
byte_size_for_type(commitment) -> 32;
byte_size_for_type(peer_pubkey) -> 32;
byte_size_for_type(state) -> 32;
@@ -309,7 +304,6 @@ byte_size_for_type(state_trees) -> not_applicable;
byte_size_for_type(call_state_tree) -> not_applicable;
byte_size_for_type(mp_tree_hash) -> 32;
byte_size_for_type(hash) -> 32;
byte_size_for_type(entry) -> not_applicable;
byte_size_for_type(bytearray) -> not_applicable.
@@ -1,22 +1,20 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% Functions for serializing chain objects to binary format.
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_chain_objects).
-vsn("0.1.2").
-module(aeser_chain_objects).
-export([ serialize/4
, deserialize/4
, deserialize_type_and_vsn/1
]).
-type template() :: gmserialization:template().
-type fields() :: gmserialization:fields().
-type template() :: aeserialization:template().
-type fields() :: aeserialization:fields().
%%%===================================================================
%%% API
@@ -24,15 +22,15 @@
-spec serialize(atom(), non_neg_integer(), template(), fields()) -> binary().
serialize(Type, Vsn, Template, Fields) ->
gmserialization:serialize(tag(Type), Vsn, Template, Fields).
aeserialization:serialize(tag(Type), Vsn, Template, Fields).
deserialize_type_and_vsn(Binary) ->
{Tag, Vsn, Fields} = gmserialization:deserialize_tag_and_vsn(Binary),
{Tag, Vsn, Fields} = aeserialization:deserialize_tag_and_vsn(Binary),
{rev_tag(Tag), Vsn, Fields}.
-spec deserialize(atom(), non_neg_integer(), template(), binary()) -> fields().
deserialize(Type, Vsn, Template, Binary) ->
gmserialization:deserialize(Type, tag(Type), Vsn, Template, Binary).
aeserialization:deserialize(Type, tag(Type), Vsn, Template, Binary).
%%%===================================================================
%%% Internal functions
@@ -41,7 +39,12 @@ deserialize(Type, Vsn, Template, Binary) ->
tag(account) -> 10;
tag(signed_tx) -> 11;
tag(spend_tx) -> 12;
tag(data_extend_tx) -> 13;
tag(oracle) -> 20;
tag(oracle_query) -> 21;
tag(oracle_register_tx) -> 22;
tag(oracle_query_tx) -> 23;
tag(oracle_response_tx) -> 24;
tag(oracle_extend_tx) -> 25;
tag(name) -> 30;
tag(name_commitment) -> 31;
tag(name_claim_tx) -> 32;
@@ -54,10 +57,8 @@ tag(contract) -> 40;
tag(contract_call) -> 41;
tag(contract_create_tx) -> 42;
tag(contract_call_tx) -> 43;
tag(contract_source) -> 44;
tag(channel_create_tx) -> 50;
tag(channel_set_delegates_tx) -> 501;
tag(channel_delegates) -> 502;
tag(channel_deposit_tx) -> 51;
tag(channel_withdraw_tx) -> 52;
tag(channel_force_progress_tx) -> 521;
@@ -84,9 +85,9 @@ tag(contracts_mtree) -> 621;
tag(calls_mtree) -> 622;
tag(channels_mtree) -> 623;
tag(nameservice_mtree) -> 624;
tag(oracles_mtree) -> 625;
tag(accounts_mtree) -> 626;
tag(acs_mtree) -> 627;
tag(entries_mtree) -> 628;
tag(compiler_sophia) -> 70;
tag(ga_attach_tx) -> 80;
tag(ga_meta_tx) -> 81;
@@ -99,28 +100,20 @@ tag(ac_create_tx) -> 93;
tag(ac_deposit_tx) -> 94;
tag(ac_update_cops_tx) -> 95;
tag(ac_rollup_tx) -> 96;
tag(ac_proposal_tx) -> 97;
tag(key_block) -> 100;
tag(micro_block) -> 101;
tag(light_micro_block) -> 102;
tag(testimony) -> 110;
tag(testimony_tx) -> 111;
tag(nt_native_token) -> 120;
tag(nt_create_tx) -> 121;
tag(nt_mint_tx) -> 122;
tag(nt_finalize_tx) -> 123;
tag(nt_trade_tx) -> 124;
tag(nt_burn_tx) -> 125;
tag(entry) -> 140;
tag(entry_create_tx) -> 141;
tag(entry_transfer_tx) -> 142;
tag(entry_destroy_tx) -> 143;
tag(pof) -> 200.
rev_tag(10) -> account;
rev_tag(11) -> signed_tx;
rev_tag(12) -> spend_tx;
rev_tag(13) -> data_extend_tx;
rev_tag(20) -> oracle;
rev_tag(21) -> oracle_query;
rev_tag(22) -> oracle_register_tx;
rev_tag(23) -> oracle_query_tx;
rev_tag(24) -> oracle_response_tx;
rev_tag(25) -> oracle_extend_tx;
rev_tag(30) -> name;
rev_tag(31) -> name_commitment;
rev_tag(32) -> name_claim_tx;
@@ -133,10 +126,8 @@ rev_tag(40) -> contract;
rev_tag(41) -> contract_call;
rev_tag(42) -> contract_create_tx;
rev_tag(43) -> contract_call_tx;
rev_tag(44) -> contract_source;
rev_tag(50) -> channel_create_tx;
rev_tag(501) -> channel_set_delegates_tx;
rev_tag(502) -> channel_delegates;
rev_tag(51) -> channel_deposit_tx;
rev_tag(52) -> channel_withdraw_tx;
rev_tag(521) -> channel_force_progress_tx;
@@ -163,9 +154,9 @@ rev_tag(621) -> contracts_mtree;
rev_tag(622) -> calls_mtree;
rev_tag(623) -> channels_mtree;
rev_tag(624) -> nameservice_mtree;
rev_tag(625) -> oracles_mtree;
rev_tag(626) -> accounts_mtree;
rev_tag(627) -> acs_mtree;
rev_tag(628) -> entries_mtree;
rev_tag(70) -> compiler_sophia;
rev_tag(80) -> ga_attach_tx;
rev_tag(81) -> ga_meta_tx;
@@ -178,20 +169,7 @@ rev_tag(93) -> ac_create_tx;
rev_tag(94) -> ac_deposit_tx;
rev_tag(95) -> ac_update_cops_tx;
rev_tag(96) -> ac_rollup_tx;
rev_tag(97) -> ac_proposal_tx;
rev_tag(100) -> key_block;
rev_tag(101) -> micro_block;
rev_tag(102) -> light_micro_block;
rev_tag(110) -> testimony;
rev_tag(111) -> testimony_tx;
rev_tag(120) -> nt_native_token;
rev_tag(121) -> nt_create_tx;
rev_tag(122) -> nt_mint_tx;
rev_tag(123) -> nt_finalize_tx;
rev_tag(124) -> nt_trade_tx;
rev_tag(125) -> nt_burn_tx;
rev_tag(140) -> entry;
rev_tag(141) -> entry_create_tx;
rev_tag(142) -> entry_transfer_tx;
rev_tag(143) -> entry_destroy_tx;
rev_tag(200) -> pof.
@@ -1,14 +1,12 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% Serialization of contract code
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_contract_code).
-vsn("0.1.2").
-module(aeser_contract_code).
-include("gmser_contract_code.hrl").
-include("aeser_contract_code.hrl").
-export([ deserialize/1
, serialize/1
@@ -18,16 +16,15 @@
serialize(CodeMap) ->
serialize(CodeMap, ?SOPHIA_CONTRACT_VSN_3).
-spec serialize(map(), non_neg_integer()) -> binary().
serialize(CodeMap = #{ byte_code := ByteCode
, type_info := TypeInfo }, SophiaContractVersion) ->
%% Source hash
SourceHash =
case CodeMap of
#{ source_hash := SHash } -> SHash;
#{ contract_source := SrcStr } -> blake2(32, list_to_binary(SrcStr))
end,
SourceHash = case CodeMap of
#{ source_hash := SHash } -> SHash;
#{ contract_source := SrcStr } ->
enacl:generichash(32, list_to_binary(SrcStr))
end,
%% Compiler version
Version = maps:get(compiler_version, CodeMap, <<"unknown">>),
@@ -45,35 +42,20 @@ serialize(CodeMap = #{ byte_code := ByteCode
|| SophiaContractVersion > ?SOPHIA_CONTRACT_VSN_1 ] ++
[ {payable, Payable}
|| SophiaContractVersion > ?SOPHIA_CONTRACT_VSN_2 ],
gmser_chain_objects:serialize(compiler_sophia,
aeser_chain_objects:serialize(compiler_sophia,
SophiaContractVersion,
serialization_template(SophiaContractVersion),
Fields).
% NOTE:
% This form significantly favors the presence of enacl and slows fallback
% invokation of eblake2. `try' is really fast; the error throwing machinery
% is comparatively slow. The assumption here is that in cases where you want
% eblake2 performance isn't the problem you're solving (you're probably not
% syncing a new node, for example).
blake2(Size, Bin) ->
try
enacl:generichash(Size, Bin)
catch error:undef ->
{ok, Hash} = eblake2:blake2b(Size, Bin),
Hash
end.
-spec deserialize(binary()) -> map().
deserialize(Binary) ->
case gmser_chain_objects:deserialize_type_and_vsn(Binary) of
case aeser_chain_objects:deserialize_type_and_vsn(Binary) of
{compiler_sophia = Type, ?SOPHIA_CONTRACT_VSN_1 = Vsn, _Rest} ->
Template = serialization_template(Vsn),
[ {source_hash, Hash}
, {type_info, TypeInfo}
, {byte_code, ByteCode}
] = gmser_chain_objects:deserialize(Type, Vsn, Template, Binary),
] = aeser_chain_objects:deserialize(Type, Vsn, Template, Binary),
#{ source_hash => Hash
, type_info => TypeInfo
, byte_code => ByteCode
@@ -86,7 +68,7 @@ deserialize(Binary) ->
, {type_info, TypeInfo}
, {byte_code, ByteCode}
, {compiler_version, CompilerVersion}
] = gmser_chain_objects:deserialize(Type, Vsn, Template, Binary),
] = aeser_chain_objects:deserialize(Type, Vsn, Template, Binary),
#{ source_hash => Hash
, type_info => TypeInfo
, byte_code => ByteCode
@@ -101,7 +83,7 @@ deserialize(Binary) ->
, {byte_code, ByteCode}
, {compiler_version, CompilerVersion}
, {payable, Payable}
] = gmser_chain_objects:deserialize(Type, Vsn, Template, Binary),
] = aeser_chain_objects:deserialize(Type, Vsn, Template, Binary),
#{ source_hash => Hash
, type_info => TypeInfo
, byte_code => ByteCode
@@ -1,16 +1,17 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2023, Aeternity Anstalt
%%% @doc
%%% Serialization of delegation signatures
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_delegation).
-vsn("0.1.2").
-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
@@ -27,7 +28,7 @@
-type sig_data() :: binary().
-spec aens_preclaim_sig(binary(), gmser_id:id(), gmser_id:id()) -> sig_data().
-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),
@@ -35,7 +36,7 @@ aens_preclaim_sig(NetworkId, Account, Contract) ->
Fields = [{account, Account}, {contract, Contract}],
serialize(?TYPE_AENS_PRECLAIM, NetworkId, Template, Fields).
-spec aens_name_sig(binary(), gmser_id:id(), gmser_id:id(), gmser_id:id()) -> sig_data().
-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),
@@ -44,7 +45,7 @@ aens_name_sig(NetworkId, Account, Name, Contract) ->
Fields = [{account, Account}, {name, Name}, {contract, Contract}],
serialize(?TYPE_AENS_NAME, NetworkId, Template, Fields).
-spec aens_sig(binary(), gmser_id:id(), gmser_id:id()) -> sig_data().
-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),
@@ -52,14 +53,29 @@ aens_sig(NetworkId, Account, Contract) ->
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 = gmserialization:serialize(Type, ?VSN, Template, Fields),
Data = aeserialization:serialize(Type, ?VSN, Template, Fields),
<<?DELEGATION_TAG:16, NetworkId/binary, Data/binary>>.
assert_id(Type, AeserId) ->
Type = gmser_id:specialize_type(AeserId).
Type = aeser_id:specialize_type(AeserId).
+7 -11
View File
@@ -1,14 +1,12 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% ADT for identifiers
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_id).
-vsn("0.1.2").
-module(aeser_id).
-export([ create/2
, specialize/1
@@ -26,9 +24,9 @@
, val
}).
-type tag() :: 'account' | 'name'
-type tag() :: 'account' | 'oracle' | 'name'
| 'commitment' | 'contract' | 'channel'
| 'associate_chain' | 'entry' .
| 'associate_chain' .
-type val() :: <<_:256>>.
-opaque(id() :: #id{}).
@@ -42,12 +40,12 @@
-define(SERIALIZED_SIZE, 33). %% ?TAG_SIZE + ?PUB_SIZE
-define(IS_TAG(___TAG___), ___TAG___ =:= account;
___TAG___ =:= oracle;
___TAG___ =:= name;
___TAG___ =:= commitment;
___TAG___ =:= contract;
___TAG___ =:= channel;
___TAG___ =:= associate_chain;
___TAG___ =:= entry
___TAG___ =:= associate_chain
).
-define(IS_VAL(___VAL___), byte_size(___VAL___) =:= 32).
@@ -101,19 +99,17 @@ decode(<<Tag:?TAG_SIZE/unit:8, Val:?PUB_SIZE/binary>>) ->
encode_tag(account) -> 1;
encode_tag(name) -> 2;
encode_tag(commitment) -> 3;
encode_tag(oracle) -> 4;
encode_tag(contract) -> 5;
encode_tag(channel) -> 6;
encode_tag(associate_chain) -> 7;
encode_tag(native_token) -> 8;
encode_tag(entry) -> 9;
encode_tag(Other) -> error({illegal_id_tag_name, Other}).
decode_tag(1) -> account;
decode_tag(2) -> name;
decode_tag(3) -> commitment;
decode_tag(4) -> oracle;
decode_tag(5) -> contract;
decode_tag(6) -> channel;
decode_tag(7) -> associate_chain;
decode_tag(8) -> native_token;
decode_tag(9) -> entry;
decode_tag(X) -> error({illegal_id_tag, X}).
+1 -5
View File
@@ -1,18 +1,14 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc
%%% Implementation of the Recursive Length Prefix.
%%%
%%% https://zxq9.com/archives/2749
%%% https://github.com/ethereum/wiki/wiki/RLP
%%%
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_rlp).
-vsn("0.1.2").
-module(aeser_rlp).
-export([ decode/1
, decode_one/1
, encode/1
@@ -1,5 +1,5 @@
{application, gmserialization,
[{description, "Serialization of data for the Gajumaru"},
{application, aeserialization,
[{description, "Serialization of data for Aeternity"},
{vsn, "0.1.0"},
{registered, []},
{applications,
@@ -1,20 +1,16 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% Functions for serializing generic objects to/from binary format.
%%% @end
%%%-------------------------------------------------------------------
-module(gmserialization).
-vsn("0.1.2").
-module(aeserialization).
-export([ decode_fields/2
, decode_field/2
, deserialize/5
, deserialize_tag_and_vsn/1
, encode_fields/2
, encode_field/2
, serialize/4 ]).
%%%===================================================================
@@ -25,8 +21,6 @@
, fields/0
]).
-export_type([ encodable_term/0 ]).
-type template() :: [{field_name(), type()}].
-type field_name() :: atom().
-type type() :: 'int'
@@ -41,9 +35,9 @@
| binary()
| boolean()
| [encodable_term()] %% Of any length
| #{atom() => encodable_term()}
| #{atom() => encodable_term()}
| tuple() %% Any arity, containing encodable_term().
| gmser_id:id().
| aeser_id:id().
-type fields() :: [{field_name(), encodable_term()}].
@@ -55,13 +49,13 @@
serialize(Tag, Vsn, Template, Fields) ->
List = encode_fields([{tag, int}, {vsn, int}|Template],
[{tag, Tag}, {vsn, Vsn}|Fields]),
gmser_rlp:encode(List).
aeser_rlp:encode(List).
%% Type isn't strictly necessary, but will give a better error reason
-spec deserialize(atom(), non_neg_integer(), non_neg_integer(),
template(), binary()) -> fields().
deserialize(Type, Tag, Vsn, Template0, Binary) ->
Decoded = gmser_rlp:decode(Binary),
Decoded = aeser_rlp:decode(Binary),
Template = [{tag, int}, {vsn, int}|Template0],
case decode_fields(Template, Decoded) of
[{tag, Tag}, {vsn, Vsn}|Left] ->
@@ -74,7 +68,7 @@ deserialize(Type, Tag, Vsn, Template0, Binary) ->
-spec deserialize_tag_and_vsn(binary()) ->
{non_neg_integer(), non_neg_integer(), fields()}.
deserialize_tag_and_vsn(Binary) ->
[TagBin, VsnBin|Fields] = gmser_rlp:decode(Binary),
[TagBin, VsnBin|Fields] = aeser_rlp:decode(Binary),
Template = [{tag, int}, {vsn, int}],
[{tag, Tag}, {vsn, Vsn}] = decode_fields(Template, [TagBin, VsnBin]),
{Tag, Vsn, Fields}.
@@ -124,7 +118,7 @@ encode_field(binary, X) when is_binary(X) -> X;
encode_field(bool, true) -> <<1:8>>;
encode_field(bool, false) -> <<0:8>>;
encode_field(id, Val) ->
try gmser_id:encode(Val)
try aeser_id:encode(Val)
catch _:_ -> error({illegal, id, Val})
end;
encode_field(Type, Val) -> error({illegal, Type, Val}).
@@ -148,7 +142,7 @@ decode_field(binary, X) when is_binary(X) -> X;
decode_field(bool, <<1:8>>) -> true;
decode_field(bool, <<0:8>>) -> false;
decode_field(id, Val) ->
try gmser_id:decode(Val)
try aeser_id:decode(Val)
catch _:_ -> error({illegal, id, Val})
end;
decode_field(Type, X) -> error({illegal, Type, X}).
-737
View File
@@ -1,737 +0,0 @@
-module(gmser_dyn).
-export([ encode/1
, encode/2
, encode_typed/2
, encode_typed/3
, decode/1
, decode/2 ]).
-export([ serialize/1
, serialize/2
, serialize_typed/2
, serialize_typed/3
, deserialize/1
, deserialize/2 ]).
%% register a type schema, inspect existing schema
-export([ register_types/1
, registered_types/0
, types_from_list/1
, revert_to_default_types/0
, dynamic_types/0 ]).
%% Register individual types, or cache labels
-export([ register_type/3
, cache_label/2 ]).
-import(gmserialization, [ decode_field/2 ]).
-define(VSN, 1).
-include_lib("kernel/include/logger.hrl").
-ifdef(TEST).
-compile([export_all, nowarn_export_all]).
-include_lib("eunit/include/eunit.hrl").
-endif.
serialize(Term) -> rlp_encode(encode(Term)).
serialize(Term, Types) -> rlp_encode(encode(Term, Types)).
serialize_typed(Type, Term) -> rlp_encode(encode_typed(Type, Term)).
serialize_typed(Type, Term, Types) -> rlp_encode(encode_typed(Type, Term, Types)).
deserialize(Binary) -> decode(rlp_decode(Binary)).
deserialize(Binary, Types) -> decode(rlp_decode(Binary), Types).
encode(Term) ->
encode(Term, registered_types()).
encode(Term, Types) ->
encode(Term, vsn(Types), Types).
encode(Term, Vsn, Types) ->
[ encode_basic(int, 0)
, encode_basic(int, Vsn)
, encode_(Term, Vsn, Types) ].
encode_typed(Type, Term) ->
encode_typed(Type, Term, registered_types()).
encode_typed(Type, Term, Types) ->
encode_typed(Type, Term, vsn(Types), Types).
encode_typed(Type, Term, Vsn, Types) ->
[ encode_basic(int, 0)
, encode_basic(int, Vsn)
, encode_typed_(Type, Term, Vsn, Types) ].
decode(Fields) ->
decode(Fields, registered_types()).
decode(Fields0, Types) ->
case decode_tag_and_vsn(Fields0) of
{0, Vsn, Fields} ->
decode_(Fields, Vsn, Types);
Other ->
error({illegal_serialization, Other})
end.
decode_tag_and_vsn([TagBin, VsnBin, Fields]) ->
{decode_basic(int, TagBin),
decode_basic(int, VsnBin),
Fields}.
dynamic_types() ->
#{ vsn => ?VSN
, codes =>
#{ 247 => negint
, 248 => int
, 249 => binary
, 250 => bool
, 251 => list
, 252 => map
, 253 => tuple
, 254 => id
, 255 => label}
, rev =>
#{ negint => 247
, int => 248
, binary => 249
, bool => 250
, list => 251
, map => 252
, tuple => 253
, id => 254
, label => 255}
, labels => #{}
, rev_labels => #{}
, templates =>
#{ negint => negint
, int => int
, binary => binary
, bool => bool
, list => list
, map => map
, tuple => tuple
, id => id
, label => label
}
}.
vsn(Types) ->
maps:get(vsn, Types, ?VSN).
registered_types() ->
case persistent_term:get({?MODULE, types}, undefined) of
undefined ->
dynamic_types();
Types when is_map(Types) ->
Types
end.
template(TagOrCode, Vsn, Types) ->
{Tag, Template} = get_template(TagOrCode, Types),
{Tag, dyn_template_(Template, Vsn)}.
get_template(Code, #{codes := Codes, templates := Ts}) when is_integer(Code) ->
Tag = maps:get(Code, Codes),
{Tag, maps:get(Tag, Ts)};
get_template(Tag, #{templates := Ts}) when is_atom(Tag) ->
{Tag, maps:get(Tag, Ts)}.
dyn_template_(F, Vsn) ->
if is_function(F, 0) -> F();
is_function(F, 1) -> F(Vsn);
true -> F
end.
find_cached_label(Lbl, #{labels := Lbls}) ->
maps:find(Lbl, Lbls).
decode_([CodeBin, Flds], Vsn, Types) ->
Code = decode_basic(int, CodeBin),
{_Tag, Template} = template(Code, Vsn, Types),
decode_from_template(Template, Flds, Vsn, Types).
encode_(Term, Vsn, Types) ->
encode_(Term, dyn(emit()), Vsn, Types).
encode_(Term, E, Vsn, Types) ->
{_Tag, Template} = auto_template(Term),
encode_from_template(Template, Term, E, Vsn, Types).
%% To control when to emit type codes:
%% If the template is predefined, it's 'not dynamic' (nodyn(E)).
%% If we are encoding against a type that's part of a predefined template,
%% we typically don't emit the type code, except at the very top.
%% So: emit type codes if the 'emit' bit is set, or if the 'dyn' bit is set.
emit() -> 2#01.
dyn() -> 2#10.
emit(E) -> E bor 2#01.
noemit(E) -> E band 2#10.
dyn(E) -> E bor 2#10.
nodyn(E) -> E band 2#01.
encode_typed_(Type, Term, Vsn, #{codes := Codes, rev := Rev} = Types) ->
case (is_map_key(Type, Codes) orelse is_map_key(Type, Rev)) of
true ->
encode_typed_(Type, Term, nodyn(emit()), Vsn, Types);
false ->
encode_maybe_template(Type, Term, Vsn, Types)
end.
encode_typed_(any, Term, _, Vsn, Types) ->
encode_(Term, dyn(emit()), Vsn, Types);
encode_typed_(Code, Term, E, Vsn, #{codes := Codes} = Types) when is_map_key(Code, Codes) ->
{_Tag, Template} = template(Code, Vsn, Types),
[encode_basic(int,Code),
encode_from_template(Template, Term, noemit(nodyn(E)), Vsn, Types)];
encode_typed_(Tag, Term, E, Vsn, #{templates := Ts, rev := Rev} = Types)
when is_map_key(Tag, Ts) ->
Template = dyn_template_(maps:get(Tag, Ts), Vsn),
Code = maps:get(Tag, Rev),
[encode_basic(int,Code),
encode_from_template(Template, Term, noemit(nodyn(E)), Vsn, Types)];
encode_typed_(MaybeTemplate, Term, _, Vsn, Types) ->
encode_maybe_template(MaybeTemplate, Term, Vsn, Types).
maybe_emit(E, Code, Enc) when E > 0 ->
[encode_basic(int, Code), Enc];
maybe_emit(0, _, Enc) ->
Enc.
encode_maybe_template(#{items := _} = Type, Term, Vsn, Types) ->
case is_map(Term) of
true ->
encode_from_template(Type, Term, emit(dyn()), Vsn, Types);
false ->
error({invalid, Type, Term})
end;
encode_maybe_template(#{alt := _} = Type, Term, Vsn, Types) ->
encode_from_template(Type, Term, Vsn, emit(dyn()), Types);
encode_maybe_template(Pat, Term, Vsn, Types) when is_list(Pat);
is_tuple(Pat) ->
encode_from_template(Pat, Term, emit(dyn()), Vsn, Types);
encode_maybe_template(Other, Term, _Vsn, _Types) ->
error({illegal_template, Other, Term}).
auto_template({id,Tag,V}) when Tag == account
; Tag == name
; Tag == commitment
; Tag == contract
; Tag == channel
; Tag == associate_chain
; Tag == entry ->
if is_binary(V) -> {id, id};
true ->
%% close, but no cigar
{tuple, tuple}
end;
auto_template(T) ->
if is_map(T) -> {map, map};
is_list(T) -> {list, list};
is_tuple(T) -> {tuple, tuple};
is_binary(T) -> {binary, binary};
is_boolean(T) -> {bool, bool};
is_atom(T) -> {label, label}; % binary_to_existing_atom()
is_integer(T),
T >= 0 -> {int, int};
is_integer(T),
T < 0 -> {negint, negint};
true ->
error({invalid_type, T})
end.
decode_from_template(any, Fld, Vsn, Types) ->
decode_(Fld, Vsn, Types);
decode_from_template(#{items := Items}, Fld, Vsn, Types) when is_list(Fld) ->
Zipped = lists:zip(Items, Fld),
lists:foldl(
fun({{K, Type}, V}, Map) ->
maps:is_key(K, Map) andalso error(badarg, duplicate_field),
Map#{K => decode_from_template({any,Type}, V, Vsn, Types)}
end, #{}, Zipped);
decode_from_template(#{alt := Alts} = T, Fld, Vsn, Types) when is_list(Alts) ->
decode_alt(Alts, Fld, T, Vsn, Types);
decode_from_template(list, Flds, Vsn, Types) ->
[decode_(F, Vsn, Types) || F <- Flds];
decode_from_template(map, Fld, Vsn, Types) ->
TupleFields = [F || F <- Fld],
Items = [decode_from_template({any,any}, T, Vsn, Types)
|| T <- TupleFields],
maps:from_list(Items);
decode_from_template(tuple, Fld, Vsn, Types) ->
Items = [decode_(F, Vsn, Types) || F <- Fld],
list_to_tuple(Items);
decode_from_template([Type], Fields, Vsn, Types) ->
[decode_from_template(Type, F, Vsn, Types)
|| F <- Fields];
decode_from_template(Type, V, Vsn, Types) when is_list(Type), is_list(V) ->
decode_fields(Type, V, Vsn, Types);
decode_from_template(Type, V, Vsn, Types) when is_tuple(Type), is_list(V) ->
Zipped = lists:zip(tuple_to_list(Type), V),
Items = [decode_from_template(T1, V1, Vsn, Types) || {T1, V1} <- Zipped],
list_to_tuple(Items);
decode_from_template(label, [C], _, #{rev_labels := RLbls}) ->
Code = decode_basic(int, C),
maps:get(Code, RLbls);
decode_from_template(Type, Fld, _, Types) when Type == int
; Type == negint
; Type == binary
; Type == bool
; Type == id
; Type == label ->
decode_basic(Type, Fld, Types).
encode_from_template(any, V, _E, Vsn, Types) ->
encode_(V, dyn(emit()), Vsn, Types);
encode_from_template(list, L, E, Vsn, Types) when is_list(L) ->
assert_type(is_list(L), list, L),
emit(E, list, Types,
[encode_(V, Vsn, Types) || V <- L]);
encode_from_template(#{items := Items}, M, E, Vsn, Types) ->
assert_type(is_map(M), map, M),
Emit = noemit(E),
emit(E, map, Types,
lists:map(
fun({K, Type}) ->
V = maps:get(K, M),
[encode_from_template(any, K, Emit, Vsn, Types),
encode_from_template(Type, V, Emit, Vsn, Types)]
end, Items));
encode_from_template(#{alt := Alts} = T, Term, E, Vsn, Types) when is_list(Alts) ->
encode_alt(Alts, Term, T, E, Vsn, Types);
encode_from_template(map, M, E, Vsn, Types) ->
assert_type(is_map(M), map, M),
Emit = emit(E),
emit(E, map, Types,
[[encode_from_template(any, K, Emit, Vsn, Types),
encode_from_template(any, V, Emit, Vsn, Types)]
|| {K, V} <- lists:sort(maps:to_list(M))]);
encode_from_template(tuple, T, E, Vsn, Types) ->
assert_type(is_tuple(T), tuple, T),
emit(E, tuple, Types,
[encode_(V, noemit(E), Vsn, Types) || V <- tuple_to_list(T)]);
encode_from_template(T, V, E, Vsn, Types) when is_tuple(T) ->
assert_type(is_tuple(V), T, V),
assert_type(tuple_size(T) =:= tuple_size(V), T, V),
Zipped = lists:zip(tuple_to_list(T), tuple_to_list(V)),
emit(E, tuple, Types,
[encode_from_template(T1, V1, noemit(E), Vsn, Types) || {T1, V1} <- Zipped]);
encode_from_template([Type] = T, List, E, Vsn, Types) ->
assert_type(is_list(List), T, List),
emit(E, list, Types,
[encode_from_template(Type, V, noemit(E), Vsn, Types) || V <- List]);
encode_from_template(Type, List, E, Vsn, Types) when is_list(Type), is_list(List) ->
encode_fields(Type, List, E, Vsn, Types);
encode_from_template(label, V, E, _, Types) ->
assert_type(is_atom(V), label, V),
emit(E, label, Types,
case find_cached_label(V, Types) of
error ->
encode_basic(label, V, E, Types);
{ok, Code} when is_integer(Code) ->
[encode_basic(int, Code)]
end);
encode_from_template(Type, V, E, _, Types) when Type == id
; Type == binary
; Type == bool
; Type == int
; Type == negint
; Type == label ->
encode_basic(Type, V, E, Types);
encode_from_template(Type, V, E, Vsn, Types) ->
encode_typed_(Type, V, E, Vsn, Types).
assert_type(true, _, _) -> ok;
assert_type(_, Type, V) -> error({illegal, Type, V}).
decode_alt([A|Alts], Fld, T, Vsn, Types) ->
try decode_from_template(A, Fld, Vsn, Types)
catch error:_ ->
decode_alt(Alts, Fld, T, Vsn, Types)
end;
decode_alt([], Fld, T, _, _) ->
error({illegal, T, Fld}).
encode_alt(Alts, Term, T, E, Vsn, Types) ->
%% Since we don't know which type may match, treat as dynamic.
encode_alt_(Alts, Term, T, dyn(E), Vsn, Types).
encode_alt_([A|Alts], Term, T, E, Vsn, Types) ->
try encode_from_template(A, Term, E, Vsn, Types)
catch error:_ ->
encode_alt_(Alts, Term, T, E, Vsn, Types)
end;
encode_alt_([], Term, T, _, _, _) ->
error({illegal, T, Term}).
%% Basically, dynamically encoding a statically defined object
encode_fields([{Field, Type}|TypesLeft],
[{Field, Val}|FieldsLeft], E, Vsn, Types) ->
[ encode_from_template(Type, Val, E, Vsn, Types)
| encode_fields(TypesLeft, FieldsLeft, E, Vsn, Types)];
encode_fields([{_Field, _Type} = FT|_TypesLeft],
[Val |_FieldsLeft], _E, _Vsn, _Types) ->
error({illegal_field, FT, Val});
encode_fields([Type|TypesLeft],
[Val |FieldsLeft], E, Vsn, Types) when is_atom(Type) ->
%% Not sure about this ...
[ encode_from_template(Type, Val, E, Vsn, Types)
| encode_fields(TypesLeft, FieldsLeft, E, Vsn, Types)];
encode_fields([], [], _, _, _) ->
[].
decode_fields([{Tag, Type}|TypesLeft],
[Field |FieldsLeft], Vsn, Types) ->
[ {Tag, decode_from_template(Type, Field, Vsn, Types)}
| decode_fields(TypesLeft, FieldsLeft, Vsn, Types)];
decode_fields([], [], _, _) ->
[].
emit(E, Tag, Types, Enc) when E > 0 ->
[emit_code(Tag, Types), Enc];
emit(0, _, _, Enc) ->
Enc.
emit_code(Tag, #{rev := Tags}) ->
encode_basic(int, maps:get(Tag, Tags)).
decode_basic(Type, [Tag,V], #{codes := Codes}) ->
case decode_basic(int, Tag) of
Code when map_get(Code, Codes) == Type ->
decode_basic(Type, V);
_ ->
error(illegal)
end;
decode_basic(Type, V, _) ->
decode_basic(Type, V).
decode_basic(label, Fld) ->
binary_to_existing_atom(decode_basic(binary, Fld), utf8);
decode_basic(negint, Fld) ->
I = gmserialization:decode_field(int, Fld),
-I;
decode_basic(Type, Fld) ->
gmserialization:decode_field(Type, Fld).
encode_basic(negint, I, _, Types) when is_integer(I), I < 0 ->
[emit_code(negint, Types), gmserialization:encode_field(int, -I)];
encode_basic(Tag, V, E, Types) when E > 0 ->
[emit_code(Tag, Types), encode_basic(Tag, V)];
encode_basic(Tag, V, 0, _) ->
encode_basic(Tag, V).
encode_basic(label, A) when is_atom(A) ->
encode_basic(binary, atom_to_binary(A, utf8));
encode_basic(Type, Fld) ->
gmserialization:encode_field(Type, Fld).
rlp_decode(Bin) ->
gmser_rlp:decode(Bin).
rlp_encode(Fields) ->
gmser_rlp:encode(Fields).
%% ===========================================================================
%% Type registration and validation code
register_types(Types) when is_map(Types) ->
Codes = maps:get(codes, Types, #{}),
Rev = rev_codes(Codes),
Templates = maps:get(templates, Types, #{}),
Labels = maps:get(labels, Types, #{}),
#{codes := Codes0, rev := Rev0, labels := Labels0, templates := Templates0} =
dynamic_types(),
Merged = #{ codes => maps:merge(Codes0, Codes)
, rev => maps:merge(Rev0, Rev)
, templates => maps:merge(Templates0, Templates)
, labels => maps:merge(Labels0, Labels) },
assert_sizes(Merged),
assert_mappings(Merged),
Merged1 = assert_label_cache(Merged),
put_types(Merged1).
put_types(Types) ->
persistent_term:put({?MODULE, types}, Types).
types_from_list(L) ->
lists:foldl(fun elem_to_type/2, dynamic_types(), L).
register_type(Code, Tag, Template) when is_integer(Code), Code >= 0 ->
#{codes := Codes, rev := Rev, templates := Temps} = Types = registered_types(),
case {is_map_key(Code, Codes), is_map_key(Tag, Rev)} of
{false, false} ->
New = Types#{ codes := Codes#{Code => Tag}
, rev := Rev#{Tag => Code}
, templates := Temps#{Tag => Template} },
put_types(New),
New;
{true, _} -> error(code_exists);
{_, true} -> error(tag_exists)
end.
cache_label(Code, Label) when is_integer(Code), Code >= 0, is_atom(Label) ->
#{labels := Lbls, rev_labels := RevLbls} = Types = registered_types(),
case {is_map_key(Label, Lbls), is_map_key(Code, RevLbls)} of
{false, false} ->
New = Types#{ labels := Lbls#{Label => Code}
, rev_labels := RevLbls#{Code => Label} },
put_types(New),
New;
{true,_} -> error(label_exists);
{_,true} -> error(code_exists)
end.
elem_to_type({Tag, Code, Template}, Acc) when is_atom(Tag), is_integer(Code) ->
#{codes := Codes, rev := Rev, templates := Temps} = Acc,
case {is_map_key(Tag, Rev), is_map_key(Code, Codes)} of
{false, false} ->
Acc#{ codes := Codes#{Code => Tag}
, rev := Rev#{Tag => Code}
, templates => Temps#{Tag => Template}
};
{true, _} -> error({duplicate_tag, Tag});
{_, true} -> error({duplicate_code, Code})
end;
elem_to_type({labels, Lbls}, Acc) ->
lists:foldl(fun add_label/2, Acc, Lbls);
elem_to_type(Elem, _) ->
error({invalid_type_list_element, Elem}).
add_label({L, Code}, #{labels := Lbls, rev_labels := RevLbls} = Acc)
when is_atom(L), is_integer(Code), Code > 0 ->
case {is_map_key(L, Lbls), is_map_key(Code, RevLbls)} of
{false, false} ->
Acc#{labels := Lbls#{L => Code},
rev_labels := RevLbls#{Code => L}};
{true, _} -> error({duplicate_label, L});
{_, true} -> error({duplicate_label_code, Code})
end;
add_label(Elem, _) ->
error({invalid_label_elem, Elem}).
revert_to_default_types() ->
persistent_term:put({?MODULE, types}, dynamic_types()).
assert_sizes(#{codes := Codes, rev := Rev, templates := Ts} = Types) ->
assert_sizes(map_size(Codes), map_size(Rev), map_size(Ts), Types).
assert_sizes(Sz, Sz, Sz, _) ->
ok;
assert_sizes(Sz, RSz, Sz, Types) when RSz =/= Sz ->
%% Wrong size reverse mapping must mean duplicate mappings
%% We auto-generate the reverse-mappings, so we know there aren't
%% too many of them
?LOG_ERROR("Reverse mapping size doesn't match codes size", []),
Codes = maps:get(codes, Types),
CodeVals = maps:values(Codes),
Duplicates = CodeVals -- lists:usort(CodeVals),
error({duplicate_mappings, Duplicates, Types});
assert_sizes(Sz, _, TSz, Types) when Sz > TSz ->
?LOG_ERROR("More codes than templates", []),
Tags = maps:keys(maps:get(rev, Types)),
Templates = maps:get(templates, Types),
Missing = [T || T <- Tags,
not is_map_key(T, Templates)],
error({missing_mappings, Missing, Types});
assert_sizes(Sz, _, TSz, Types) when TSz > Sz ->
%% More mappings than codes. May not be horrible.
%% We check that all codes have mappings elsewhere.
?LOG_WARNING("More templates than codes in ~p", [Types]),
ok.
assert_mappings(#{rev := Rev, templates := Ts} = Types) ->
Tags = maps:keys(Rev),
case [T || T <- Tags,
not is_map_key(T, Ts)] of
[] ->
ok;
Missing ->
?LOG_ERROR("Missing templates for ~p", [Missing]),
error({missing_templates, Missing, Types})
end.
assert_label_cache(#{labels := Labels} = Types) ->
Ls = maps:keys(Labels),
case [L || L <- Ls, not is_atom(L)] of
[] -> ok;
_NonAtoms ->
error(non_atoms_in_label_cache)
end,
Rev = [{C,L} || {L,C} <- maps:to_list(Labels)],
case [C || {C,_} <- Rev, not is_integer(C)] of
[] -> ok;
_NonInts -> error(non_integer_label_cache_codes)
end,
RevLabels = maps:from_list(Rev),
case map_size(RevLabels) == map_size(Labels) of
true ->
Types#{rev_labels => RevLabels};
false ->
error(non_unique_label_cache_codes)
end.
rev_codes(Codes) ->
L = maps:to_list(Codes),
maps:from_list([{V, K} || {K, V} <- L]).
%% ===========================================================================
%% Unit tests
-ifdef(TEST).
trace() ->
dbg:tracer(),
dbg:tpl(?MODULE, x),
dbg:p(all, [c]).
notrace() ->
dbg:ctpl('_'),
dbg:stop().
round_trip_test_() ->
[?_test(t_round_trip(T)) ||
T <- t_sample_types()
].
t_sample_types() ->
[ 5
, -5
, <<"a">>
, [1,2,3]
, {<<"a">>,1}
, #{<<"a">> => 1}
, [#{1 => <<"c">>, [17] => true}]
, true
].
user_types_test_() ->
{foreach,
fun() ->
revert_to_default_types()
end,
fun(_) ->
revert_to_default_types()
end,
[ ?_test(t_reg_typed_tuple())
, ?_test(t_reg_chain_objects_array())
, ?_test(t_reg_template_fun())
, ?_test(t_reg_template_vsnd_fun())
, ?_test(t_reg_label_cache())
, ?_test(t_reg_label_cache2())
]}.
dynamic_types_test_() ->
[ ?_test(revert_to_default_types())
, ?_test(t_typed_map())
, ?_test(t_alts())
].
t_round_trip(T) ->
?debugVal(T),
?assertMatch({T, T}, {T, decode(encode(T))}).
t_round_trip_typed(Type, T) ->
?debugVal(T),
?assertMatch({T, T}, {T, decode(encode_typed(Type, T))}).
t_reg_typed_tuple() ->
Type = {int, int, int},
MyTypes = #{ codes => #{ 1001 => int_tup3 }
, templates => #{ int_tup3 => Type }
},
register_types(MyTypes),
GoodTerm = {2,3,4},
?debugFmt("Type: ~p, GoodTerm = ~p", [Type, GoodTerm]),
Enc = encode_typed(int_tup3, GoodTerm),
GoodTerm = decode(Enc),
t_bad_typed_encode(int_tup3, {1,2,<<"a">>}, {illegal,int,<<"a">>}),
t_bad_typed_encode(int_tup3, {1,2,3,4}, {illegal, {int,int,int}, {1,2,3,4}}).
t_bad_typed_encode(Type, Term, Error) ->
try encode_typed(Type, Term),
error({expected_error, Error})
catch
error:Error ->
ok
end.
t_reg_chain_objects_array() ->
Template = [{foo, {int, binary}}, {bar, [{int, int}]}, {baz, {int}}],
?debugFmt("Template = ~p", [Template]),
MyTypes = #{ codes => #{ 1002 => coa }
, templates => #{ coa => Template } },
register_types(MyTypes),
Values = [{foo, {1, <<"foo">>}}, {bar, [{1, 2}, {3, 4}, {5, 6}]}, {baz, {1}}],
?debugFmt("Values = ~p", [Values]),
Enc = encode_typed(coa, Values),
Values = decode(Enc).
t_reg_template_fun() ->
Template = fun() -> {int,int} end,
New = register_type(1010, tup2f0, Template),
?debugFmt("New = ~p", [New]),
E = encode_typed(tup2f0, {3,4}),
{3,4} = decode(E),
ok.
t_reg_template_vsnd_fun() ->
Template = fun(1) -> {int,int} end,
New = register_type(1011, tup2f1, Template),
?debugFmt("New = ~p", [New]),
E = encode_typed(tup2f1, {3,4}),
{3,4} = decode(E),
ok.
t_reg_label_cache() ->
Enc0 = gmser_dyn:encode('1'),
?debugFmt("Enc0 (no cache): ~w", [Enc0]),
MyTypes1 = #{codes => #{1003 => lbl_tup2}, templates => #{ lbl_tup2 => {label,label} }},
register_types(MyTypes1),
Enc0a = gmser_dyn:encode_typed(lbl_tup2, {'1','1'}),
?debugFmt("Enc0a (no cache): ~w", [Enc0a]),
{'1','1'} = gmser_dyn:decode(Enc0a),
MyTypes2 = MyTypes1#{labels => #{'1' => 49}}, % atom_to_list('1') == [49]
register_types(MyTypes2),
Enc1 = gmser_dyn:encode('1'),
Enc1a = gmser_dyn:encode_typed(lbl_tup2, {'1','1'}),
?debugFmt("Enc1 (w/ cache): ~w", [Enc1]),
?debugFmt("Enc1a (w/ cache): ~w", [Enc1a]),
{'1','1'} = gmser_dyn:decode(Enc1a),
true = Enc0 =/= Enc1,
Enc2 = gmser_dyn:encode_typed(label, '1'),
?debugFmt("Enc2 (typed): ~w", [Enc2]),
?assertEqual(Enc2, Enc1),
?assertNotEqual(Enc0a, Enc1a).
t_reg_label_cache2() ->
TFromL = gmser_dyn:types_from_list(
[ {lbl_tup2, 1003, {label, label}}
, {labels,
[{'1', 49}]}
]),
?debugFmt("TFromL = ~w", [TFromL]),
register_types(TFromL),
Tup = {'1', '1'},
Enc = gmser_dyn:encode_typed(lbl_tup2, Tup),
[<<0>>,<<1>>,[<<3,235>>,[[<<49>>],[<<49>>]]]] = Enc,
_Tup = gmser_dyn:decode(Enc).
t_typed_map() ->
Term = #{a => 13, {key,1} => [a]},
Enc = encode_typed(#{items => [{a,int},{{key,1},[label]}]}, Term),
?assertEqual(Term, decode(Enc)).
t_alts() ->
t_round_trip_typed(#{alt => [negint, int]}, -4),
t_round_trip_typed(#{alt => [negint, int]}, 4),
ok.
-endif.
@@ -1,13 +1,12 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%%-------------------------------------------------------------------
-module(gmser_api_encoder_tests).
-module(aeser_api_encoder_tests).
-include_lib("eunit/include/eunit.hrl").
-define(TEST_MODULE, gmser_api_encoder).
-define(TEST_MODULE, aeser_api_encoder).
-define(TYPES, [ {key_block_hash , 32}
, {micro_block_hash , 32}
, {block_tx_hash , 32}
@@ -16,10 +15,11 @@
, {contract_pubkey , 32}
, {transaction , not_applicable}
, {tx_hash , 32}
, {oracle_pubkey , 32}
, {oracle_query_id , 32}
, {account_pubkey , 32}
, {signature , 64}
, {name , not_applicable}
, {native_token , 32}
, {commitment , 32}
, {peer_pubkey , 32}
, {state , 32}
@@ -1,12 +1,11 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc
%%% EUnit tests for gmser_chain_objects
%%% EUnit tests for aeser_chain_objects
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_chain_objects_tests).
-module(aeser_chain_objects_tests).
-include_lib("eunit/include/eunit.hrl").
@@ -79,10 +78,10 @@ deserialize(Template, Bin) ->
deserialize(Template, Bin, ?DEFAULT_TAG, ?DEFAULT_VERSION).
deserialize(Template, Bin, Tag, Vsn) ->
gmser_chain_objects:deserialize(Tag, Vsn, Template, Bin).
aeser_chain_objects:deserialize(Tag, Vsn, Template, Bin).
serialize(Template, Bin) ->
serialize(Template, Bin, ?DEFAULT_TAG, ?DEFAULT_VERSION).
serialize(Template, Bin, Tag, Vsn) ->
gmser_chain_objects:serialize(Tag, Vsn, Template, Bin).
aeser_chain_objects:serialize(Tag, Vsn, Template, Bin).
@@ -1,11 +1,7 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%%-------------------------------------------------------------------
-module(gmser_contract_code_tests).
-module(aeser_contract_code_tests).
-include_lib("eunit/include/eunit.hrl").
-include("gmser_contract_code.hrl").
-include("aeser_contract_code.hrl").
-define(DUMMY_CODE_MAP_1,
#{ byte_code => <<"DUMMY CODE">>
@@ -26,14 +22,14 @@
, payable => true} ).
vsn_1_test() ->
gmser_contract_code:deserialize(
gmser_contract_code:serialize(?DUMMY_CODE_MAP_1, ?SOPHIA_CONTRACT_VSN_1)).
aeser_contract_code:deserialize(
aeser_contract_code:serialize(?DUMMY_CODE_MAP_1, ?SOPHIA_CONTRACT_VSN_1)).
vsn_2_test() ->
gmser_contract_code:deserialize(
gmser_contract_code:serialize(?DUMMY_CODE_MAP_2, ?SOPHIA_CONTRACT_VSN_2)).
aeser_contract_code:deserialize(
aeser_contract_code:serialize(?DUMMY_CODE_MAP_2, ?SOPHIA_CONTRACT_VSN_2)).
vsn_3_test() ->
gmser_contract_code:deserialize(
gmser_contract_code:serialize(?DUMMY_CODE_MAP_3, ?SOPHIA_CONTRACT_VSN_3)).
aeser_contract_code:deserialize(
aeser_contract_code:serialize(?DUMMY_CODE_MAP_3, ?SOPHIA_CONTRACT_VSN_3)).
+67
View File
@@ -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}
].
@@ -1,11 +1,10 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Tests for Recursive Length Prefix
%%% @end
%%%-------------------------------------------------------------------
-module(gmser_rlp_tests).
-module(aeser_rlp_tests).
-include_lib("eunit/include/eunit.hrl").
@@ -14,7 +13,7 @@
-define(BYTE_ARRAY_OFFSET , 128).
-define(LIST_OFFSET , 192).
-define(TEST_MODULE, gmser_rlp).
-define(TEST_MODULE, aeser_rlp).
rlp_one_byte_test() ->
B = <<42>>,
-49
View File
@@ -1,49 +0,0 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2023, Aeternity Anstalt
%%%-------------------------------------------------------------------
-module(gmser_delegation_tests).
-include_lib("eunit/include/eunit.hrl").
-define(TEST_MODULE, gmser_delegation).
-define(ACCOUNT, gmser_id:create(account, <<1:256>>)).
-define(CONTRACT, gmser_id:create(contract, <<2:256>>)).
-define(NAME, gmser_id:create(name, <<3:256>>)).
-define(NETWORK_ID, <<"my_fancy_network"/utf8>>).
encode_correct_test_() ->
[{"Encode preclaim sig",
fun() ->
gmser_delegation:aens_preclaim_sig(?NETWORK_ID, ?ACCOUNT, ?CONTRACT)
end},
{"Encode name sig",
fun() ->
gmser_delegation:aens_name_sig(?NETWORK_ID, ?ACCOUNT, ?NAME, ?CONTRACT)
end},
{"Encode aens wildcard sig",
fun() ->
gmser_delegation:aens_sig(?NETWORK_ID, ?ACCOUNT, ?CONTRACT)
end}
].
encode_fail_test_() ->
[{"Bad encoding preclaim sig",
fun() ->
?assertError(_, gmser_delegation:aens_preclaim_sig(?NETWORK_ID, <<42:256>>, ?CONTRACT)),
?assertError(_, gmser_delegation:aens_preclaim_sig(?NETWORK_ID, ?CONTRACT, ?ACCOUNT))
end},
{"Bad encoding name sig",
fun() ->
?assertError(_, gmser_delegation:aens_name_sig(?NETWORK_ID, ?ACCOUNT, <<42:256>>, ?CONTRACT)),
?assertError(_, gmser_delegation:aens_name_sig(?NETWORK_ID, ?NAME, ?ACCOUNT, ?CONTRACT))
end},
{"Bad encoding aens wildcard sig",
fun() ->
?assertError(_, gmser_delegation:aens_sig(?NETWORK_ID, ?ACCOUNT, <<42:256>>)),
?assertError(_, gmser_delegation:aens_sig(?NETWORK_ID, ?CONTRACT, ?CONTRACT))
end}
].
-17
View File
@@ -1,17 +0,0 @@
{name,"Gajumaru Serialization"}.
{type,lib}.
{modules,[]}.
{prefix,none}.
{author,"Hans Svensson"}.
{desc,"Serialization helpers for the Gajumaru."}.
{package_id,{"otpr","gmserialization",{0,1,2}}}.
{deps,[{"otpr","eblake2",{1,0,1}},{"otpr","base58",{0,1,1}}]}.
{key_name,none}.
{a_email,[]}.
{c_email,[]}.
{copyright,"QPQ AG"}.
{file_exts,[]}.
{license,skip}.
{repo_url,"https://git.qpq.swiss/QPQ-AG/gmserialization"}.
{tags,["blockchain","crypto","gm","gajumaru"]}.
{ws_url,[]}.