From a5bfdf63d544179cef2570561498a42cd16728d2 Mon Sep 17 00:00:00 2001 From: Thomas Arts Date: Wed, 29 May 2019 15:38:52 +0200 Subject: [PATCH] Define a specific sorting for key-Value pairs Sort on key and check: no duplicates and no maps and variants as key --- src/aeb_fate_code.erl | 2 +- src/aeb_fate_encoding.erl | 49 ++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/aeb_fate_code.erl b/src/aeb_fate_code.erl index 1c6b5a3..3a1efe9 100644 --- a/src/aeb_fate_code.erl +++ b/src/aeb_fate_code.erl @@ -302,7 +302,7 @@ deserialize_functions(<>, Program#{ BB => lists:reverse(Code)}}}}, deserialize_functions(Rest2, Env2) end; -deserialize_functions(<>, +deserialize_functions(<<_Op:8, _Rest/binary>>, #{ function := none }) -> error({code_without_function}); deserialize_functions(<>, diff --git a/src/aeb_fate_encoding.erl b/src/aeb_fate_encoding.erl index 582839e..3bc3529 100644 --- a/src/aeb_fate_encoding.erl +++ b/src/aeb_fate_encoding.erl @@ -163,11 +163,12 @@ serialize(L) when ?IS_FATE_LIST(L) -> <> end; serialize(Map) when ?IS_FATE_MAP(Map) -> - L = lists:sort(maps:to_list(?FATE_MAP_VALUE(Map))), + L = maps:to_list(?FATE_MAP_VALUE(Map)), Size = length(L), %% TODO: check all K same type, and all V same type %% check K =/= map - Elements = << <<(serialize(K1))/binary, (serialize(V1))/binary>> || {K1,V1} <- L >>, + Elements = + list_to_binary([ <<(serialize(K))/binary, (serialize(V))/binary>> || {K, V} <- sort_and_check(L) ]), <>; @@ -385,8 +386,14 @@ deserialize2(<>) -> deserialize2(<>) -> {Size, Rest1} = rlp_decode_int(Rest), {List, Rest2} = deserialize_elements(2*Size, Rest1), - Map = insert_kv(List, #{}), - {?MAKE_FATE_MAP(Map), Rest2}; + KVList = insert_kv(List), + case sort_and_check(KVList) == KVList of + true -> + Map = maps:from_list(KVList), + {?MAKE_FATE_MAP(Map), Rest2}; + false -> + error({unknown_map_serialization_format, KVList}) + end; deserialize2(<>) -> {AritiesBin, <>} = aeser_rlp:decode_one(Rest), Arities = binary_to_list(AritiesBin), @@ -403,8 +410,8 @@ deserialize2(<>) -> end end. -insert_kv([], M) -> M; -insert_kv([K,V|R], M) -> insert_kv(R, maps:put(K, V, M)). +insert_kv([]) -> []; +insert_kv([K, V | R]) -> [{K, V} | insert_kv(R)]. deserialize_elements(0, Rest) -> {[], Rest}; @@ -412,3 +419,33 @@ deserialize_elements(N, Es) -> {E, Rest} = deserialize2(Es), {Tail, Rest2} = deserialize_elements(N-1, Rest), {[E|Tail], Rest2}. + + +%% It is important to rem ove duplicated keys. +%% For deserialize this check is needed to observe illegal duplicates. +sort_and_check(List) -> + UniqKeyList = + lists:foldr(fun({K, V}, Acc) -> + case valid_key_type(K) andalso not lists:keymember(K, 1, Acc) of + true -> [{K,V}|Acc]; + false -> Acc + end + end, [], List), + sort(UniqKeyList). + +%% Sorting is used to get a unique result. +%% Deserialization is checking whether the provided key-value pairs are sorted +%% and raises an exception if not. + +sort(KVList) -> + SortFun = fun({K1, _}, {K2, _}) -> + K1 =< K2 + end, + lists:sort(SortFun, KVList). + +valid_key_type(K) when ?IS_FATE_MAP(K) -> + error({map_as_key_in_map, K}); +valid_key_type(K) when ?IS_FATE_VARIANT(K) -> + error({variant_as_key_in_map, K}); +valid_key_type(_K) -> + true.