Ulf Wiger ba771836fb
All checks were successful
Gajumaru Serialization Tests / tests (push) Successful in 49m9s
Document static, make anyint standard
2025-04-11 16:39:06 +02:00

2.7 KiB

Static Serialization

The gmserialization and gmser_chain_objects modules implement the static serialization support used in the Gajumaru blockchain.

The purpose is to produce fully deterministic serialization, in order to maintain predictable hashing.

Example:

%% deterministic canonical serialization.
-spec serialize_to_binary(signed_tx()) -> binary_signed_tx().
serialize_to_binary(#signed_tx{tx = Tx, signatures = Sigs}) ->
    gmser_chain_objects:serialize(
      ?SIG_TX_TYPE,
      ?SIG_TX_VSN,
      serialization_template(?SIG_TX_VSN),
      [ {signatures, lists:sort(Sigs)}
      , {transaction, aetx:serialize_to_binary(Tx)}
      ]).

-spec deserialize_from_binary(binary()) -> signed_tx().
deserialize_from_binary(SignedTxBin) when is_binary(SignedTxBin) ->
    [ {signatures, Sigs}
    , {transaction, TxBin}
    ] = gmser_chain_objects:deserialize(
          ?SIG_TX_TYPE,
          ?SIG_TX_VSN,
          serialization_template(?SIG_TX_VSN),
          SignedTxBin),
    assert_sigs_size(Sigs),
    #signed_tx{ tx = aetx:deserialize_from_binary(TxBin)
              , signatures = Sigs
              }.

serialization_template(?SIG_TX_VSN) ->
    [ {signatures, [binary]}
    , {transaction, binary}
    ].

The terms that can be encoded using these templates are given by this type in gmserialization.erl:

-type encodable_term() :: non_neg_integer()
                        | binary()
                        | boolean()
                        | [encodable_term()] %% Of any length
                        | #{atom() => encodable_term()}
                        | tuple()  %% Any arity, containing encodable_term().
                        | gmser_id:id().

The template 'language' is defined by these types:

-type template() :: [{field_name(), type()}].
-type field_name() :: atom().
-type type() :: 'int'
              | 'bool'
              | '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.

The gmser_chain_objects.erl module specifies a serialization code for each object that can go on-chain. E.g.:

tag(signed_tx) -> 11;
...
rev_tag(11) -> signed_tx;

The tag and vsn are laid out in the beginning of the serialized object.