From 429175f2350013415888c7bfe057536240e9f5f6 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Mon, 25 Mar 2019 13:30:44 +0100 Subject: [PATCH] Use aeserialization for base58c encoding/decoding. --- README.md | 26 ++++----- src/aeb_fate_asm.erl | 26 ++++----- src/aeb_fate_asm_scan.template | 65 ++++++---------------- src/aeb_fate_data.erl | 86 ++++++++++++----------------- test/asm_code/all_instructions.fate | 6 +- test/asm_code/immediates.fate | 2 +- 6 files changed, 80 insertions(+), 131 deletions(-) diff --git a/README.md b/README.md index cb0d261..41ecff0 100644 --- a/README.md +++ b/README.md @@ -58,22 +58,23 @@ Immediate values can be of 11 types: `0x0deadbeef0` 2. Chain Objects. These are all addresses to different types of chain objects. - Each address is a 256 bits number encoded in base64 with a prefix. + Each address is a 256 bits number encoded in base58 with checksum + with a prefix of "@" plus a type prefix followed by "_". -2a. Address: a base58 encoded number starting with @ followed by a number of base58chars - `@nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` +2a. Account Address: a base58c encoded number starting with @ak_ followed by a number of base58chars + '@ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` -2b. Contract address: ct_{base58char}+ - `ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` +2b. Contract address: @ct_{base58char}+ + `@ct_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` -2c. Oracle address: ok_{base58char}+ - `ok_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` +2c. Oracle address: @ok_{base58char}+ + `@ok_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` -2d. Name address: nm_{base58char}+ - `nm_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` +2d. Name address: @nm_{base58char}+ + `@nm_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` -2e. Channel address: ch_{base58char}+ - `ch_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` +2e. Channel address: @ch_{base58char}+ + `@ch_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv` 3. Boolean true or false `true` @@ -106,8 +107,7 @@ Immediate values can be of 11 types: 10. Hashes: #{base64char}+ `#AQIDCioLFQ==` -11. Signatures: ${base64char}+ - `$AQIDCioLFQ==` +11. Signatures: $sg_{base58char}+ Where diff --git a/src/aeb_fate_asm.erl b/src/aeb_fate_asm.erl index 3501081..708dea5 100644 --- a/src/aeb_fate_asm.erl +++ b/src/aeb_fate_asm.erl @@ -40,12 +40,11 @@ %%% -2374683271468723648732648736498712634876147 %%% 1b. Integers as Hexadecimals:: 0x{Hexdigits} %%% 0x0deadbeef0 -%%% 2a. addresses, a base58 encoded string prefixed with @ -%%% @foo -%%% 2b. contract address: ct_{base58char}+ -%%% 2c. oracle address: ok_{base58char}+ -%%% 2d. name address: nm_{base58char}+ -%%% 2e. channel address: ch_{base58char}+ +%%% 2a. account addresses, a base58c encoded string prefixed with @ak_ +%%% 2b. contract address: @ct_{base58char}+ +%%% 2c. oracle address: @ok_{base58char}+ +%%% 2d. name address: @nm_{base58char}+ +%%% 2e. channel address: @ch_{base58char}+ %%% 3. Boolean true or false %%% true %%% false @@ -69,8 +68,7 @@ %%% (| 42 | 12 | ( "foo", 12) |) %%% 10. Hashes: #{base64char}+ %%% #AQIDCioLFQ== -%%% 11. Signatures: ${base64char}+ -%%% $AQIDCioLFQ== +%%% 11. Signatures: $sg_{base58char}+ %%% %%% Where Digits: [0123456789] %%% Hexdigits: [0123456789abcdef] @@ -761,27 +759,27 @@ to_bytecode([{string,_line, String}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_string(String)}|Code], Opts); -to_bytecode([{address,_line, {address, Value}}|Rest], +to_bytecode([{object,_line, {address, Value}}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_address(Value)}|Code], Opts); -to_bytecode([{address,_line, {contract, Value}}|Rest], +to_bytecode([{object,_line, {contract, Value}}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_contract(Value)}|Code], Opts); -to_bytecode([{address,_line, {oracle, Value}}|Rest], +to_bytecode([{object,_line, {oracle, Value}}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_oracle(Value)}|Code], Opts); -to_bytecode([{address,_line, {name, Value}}|Rest], +to_bytecode([{object,_line, {name, Value}}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_name(Value)}|Code], Opts); -to_bytecode([{address,_line, {channel, Value}}|Rest], +to_bytecode([{object,_line, {channel, Value}}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_contract(Value)}|Code], @@ -791,7 +789,7 @@ to_bytecode([{hash,_line, Value}|Rest], to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_hash(Value)}|Code], Opts); -to_bytecode([{signature,_line, Value}|Rest], +to_bytecode([{signature,_line, {signature, Value}}|Rest], Address, Env, Code, Opts) -> to_bytecode(Rest, Address, Env, [{immediate, aeb_fate_data:make_signature(Value)}|Code], diff --git a/src/aeb_fate_asm_scan.template b/src/aeb_fate_asm_scan.template index c9013dc..b5da2b7 100644 --- a/src/aeb_fate_asm_scan.template +++ b/src/aeb_fate_asm_scan.template @@ -16,10 +16,9 @@ BASE58 = [123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz] BASE64 = [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy0123456789+/=] INT = {DIGIT}+ HEX = 0x{HEXDIGIT}+ -OBJECT = [a-z][a-z]_{BASE58}+ -ADDRESS = @{BASE58}+ +OBJECT = @[a-z][a-z]_{BASE58}+ HASH = #{BASE64}+ -SIG = \${BASE64}+ +SIG = \$\sg_{BASE58}+ WS = [\000-\s] ID = {LOWER}[a-zA-Z0-9_]* STRING = "[^"]*" @@ -38,6 +37,12 @@ false : {token, {boolean, TokenLine, false}}. FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}. +{HASH} : + {token, {hash, TokenLine, parse_hash(TokenChars)}}. +{SIG} : + {token, {signature, TokenLine, parse_object(TokenChars)}}. +{OBJECT} : + {token, {object, TokenLine, parse_object(TokenChars)}}. {ID} : {token, {id, TokenLine, TokenChars}}. {HEX} : @@ -46,14 +51,6 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}. {token, {int, TokenLine, parse_int(TokenChars)}}. -{INT} : {token, {int, TokenLine, parse_int(TokenChars)}}. -{HASH} : - {token, {hash, TokenLine, parse_hash(TokenChars)}}. -{SIG} : - {token, {signature, TokenLine, parse_signature(TokenChars)}}. -{ADDRESS} : - {token, {address, TokenLine, {address, parse_address(TokenChars)}}}. -{OBJECT} : - {token, {object, TokenLine, parse_object(TokenChars)}}. {STRING} : {token, {string, TokenLine, list_to_binary(TokenChars)}}. {BITS} : @@ -114,23 +111,15 @@ parse_acc("a" ++ N) -> list_to_integer(N). parse_hash("#" ++ Chars) -> base64:decode(Chars). -parse_signature("$" ++ Chars) -> - base64:decode(Chars). - -parse_address("@" ++ Chars) -> - base58_to_address(Chars). - -parse_object("ct_" ++ Chars) -> - {contract, base58_to_address(Chars)}; -parse_object("ok_" ++ Chars) -> - {oracle, base58_to_address(Chars)}; -parse_object("nm_" ++ Chars) -> - {name, base58_to_address(Chars)}; -parse_object("ch_" ++ Chars) -> - {channel, base58_to_address(Chars)}; -parse_object("ak_" ++ Chars) -> - {address, base58_to_address(Chars)}. - +parse_object([_|Chars]) -> + case aeser_api_encoder:decode(list_to_binary(Chars)) of + {account_pubkey, Bin} -> {address, Bin}; + {contract_pubkey, Bin} -> {contract, Bin}; + {oracle_pubkey, Bin} -> {oracle, Bin}; + {name, Bin} -> {name, Bin}; + {channel, Bin} -> {channel, Bin}; + {signature, Bin} -> {signature, Bin} + end. scan(S) -> string(S). @@ -148,23 +137,3 @@ bits([$> |_Rest], Acc) -> Acc; bits([$0 | Rest], Acc) -> bits(Rest, Acc bsl 1); bits([$1 | Rest], Acc) -> bits(Rest, (Acc bsl 1) bor 1); bits([$ | Rest], Acc) -> bits(Rest, Acc). - -char_to_base58(C) -> - binary:at(<<0,1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,9,10,11,12,13,14,15,16,0,17, - 18,19,20,21,0,22,23,24,25,26,27,28,29,30,31,32,0,0,0,0,0,0, - 33,34,35,36,37,38,39,40,41,42,43,0,44,45,46,47,48,49,50,51, - 52,53,54,55,56,57>>, C-$1). - -base58_to_integer(C, []) -> C; -base58_to_integer(C, [X | Xs]) -> - base58_to_integer(C * 58 + char_to_base58(X), Xs). - -base58_to_integer([]) -> error; -base58_to_integer([Char]) -> char_to_base58(Char); -base58_to_integer([Char | Str]) -> - base58_to_integer(char_to_base58(Char), Str). - -base58_to_address(Base58) -> - I = base58_to_integer(Base58), - Bin = <>, - Bin. diff --git a/src/aeb_fate_data.erl b/src/aeb_fate_data.erl index d7bfef7..1454524 100644 --- a/src/aeb_fate_data.erl +++ b/src/aeb_fate_data.erl @@ -137,23 +137,29 @@ encode({bits, Term}) when is_integer(Term) -> make_bits(Term); %% TODO: check that each byte is in base58 encode({address, B}) when is_binary(B) -> make_address(B); encode({address, I}) when is_integer(I) -> B = <>, make_address(B); -encode({address, S}) when is_list(S) -> make_address(base58_to_address(S)); +encode({address, S}) when is_list(S) -> + make_address(encode_address(account_pubkey, S)); encode({hash, H}) when is_binary(H) -> make_hash(H); encode({hash, H}) when is_list(H) -> make_hash(base64:decode(H)); encode({signature, S}) when is_binary(S) -> make_signature(S); -encode({signature, S}) when is_list(S) -> make_signature(base64:decode(S)); +encode({signature, S}) when is_list(S) -> + make_signature(encode_address(signature, S)); encode({contract, B}) when is_binary(B) -> make_contract(B); encode({contract, I}) when is_integer(I) -> B = <>, make_contract(B); -encode({contract, S}) when is_list(S) -> make_contract(base58_to_address(S)); +encode({contract, S}) when is_list(S) -> + make_contract(encode_address(contract_pubkey, S)); encode({oracle, B}) when is_binary(B) -> make_oracle(B); encode({oracle, I}) when is_integer(I) -> B = <>, make_oracle(B); -encode({oracle, S}) when is_list(S) -> make_oracle(base58_to_address(S)); +encode({oracle, S}) when is_list(S) -> + make_oracle(encode_address(oracle_pubkey, S)); encode({name, B}) when is_binary(B) -> make_name(B); encode({name, I}) when is_integer(I) -> B = <>, make_name(B); -encode({name, S}) when is_list(S) -> make_name(base58_to_address(S)); +encode({name, S}) when is_list(S) -> + make_name(encode_address(name, S)); encode({channel, B}) when is_binary(B) -> make_channel(B); encode({channel, I}) when is_integer(I) -> B = <>, make_channel(B); -encode({channel, S}) when is_list(S) -> make_channel(base58_to_address(S)); +encode({channel, S}) when is_list(S) -> + make_channel(encode_address(channel, S)); encode({variant, Size, Tag, Values}) -> make_variant(Size, Tag, Values); encode(Term) when is_integer(Term) -> make_integer(Term); encode(Term) when is_boolean(Term) -> make_boolean(Term); @@ -205,13 +211,19 @@ format(?FATE_VARIANT(Size, Tag, T)) -> " |)"]; format(M) when ?IS_FATE_MAP(M) -> ["{ ", format_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"]; -format(?FATE_ADDRESS(Address)) -> ["@", address_to_base58(Address)]; -format(?FATE_HASH(X)) -> ["#", base64:encode(X)]; -format(?FATE_SIGNATURE(X)) -> ["$", base64:encode(X)]; -format(?FATE_CONTRACT(X)) -> ["ct_", address_to_base58(X)]; -format(?FATE_ORACLE(X)) -> ["ok_", address_to_base58(X)]; -format(?FATE_NAME(X)) -> ["nm_", address_to_base58(X)]; -format(?FATE_CHANNEL(X)) -> ["ch_", address_to_base58(X)]; +format(?FATE_HASH(X)) -> ["#", base64:encode(X)]; +format(?FATE_ADDRESS(X)) -> + ["@", aeser_api_encoder:encode(account_pubkey, X)]; +format(?FATE_SIGNATURE(X)) -> + ["$", aeser_api_encoder:encode(signature, X)]; +format(?FATE_CONTRACT(X)) -> + ["@", aeser_api_encoder:encode(contract_pubkey, X)]; +format(?FATE_ORACLE(X)) -> + ["@", eser_api_encoder:encode(oracle_pubkey, X)]; +format(?FATE_NAME(X)) -> + ["@", aeser_api_encoder:encode(name, X)]; +format(?FATE_CHANNEL(X)) -> + ["@", aeser_api_encoder:encode(channel, X)]; format(V) -> exit({not_a_fate_type, V}). format_bits(0, Acc) -> Acc; @@ -230,42 +242,12 @@ format_list(List) -> format_kvs(List) -> lists:join(", ", [ [format(K), " => ", format(V)] || {K, V} <- List]). - -%% -- Local base 58 library - -base58char(Char) -> - binary:at(<<"123456789ABCDEFGHJKLMNPQRSTUVWXYZ" - "abcdefghijkmnopqrstuvwxyz">>, Char). -char_to_base58(C) -> - binary:at(<<0,1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,9,10,11,12,13,14,15,16,0,17, - 18,19,20,21,0,22,23,24,25,26,27,28,29,30,31,32,0,0,0,0,0,0, - 33,34,35,36,37,38,39,40,41,42,43,0,44,45,46,47,48,49,50,51, - 52,53,54,55,56,57>>, C-$1). - -base58_to_integer(C, []) -> C; -base58_to_integer(C, [X | Xs]) -> - base58_to_integer(C * 58 + char_to_base58(X), Xs). - -base58_to_integer([]) -> error; -base58_to_integer([Char]) -> char_to_base58(Char); -base58_to_integer([Char | Str]) -> - base58_to_integer(char_to_base58(Char), Str). - -base58_to_address(Base58) -> - I = base58_to_integer(Base58), - Bin = <>, - Bin. - -address_to_base58(<>) -> - integer_to_base58(A). - -integer_to_base58(0) -> <<"1">>; -integer_to_base58(Integer) -> - Base58String = integer_to_base58(Integer, []), - list_to_binary(Base58String). - -integer_to_base58(0, Acc) -> Acc; -integer_to_base58(Integer, Acc) -> - Quot = Integer div 58, - Rem = Integer rem 58, - integer_to_base58(Quot, [base58char(Rem)|Acc]). +encode_address(Type, S) when is_list(S) -> + B = list_to_binary(S), + try aeser_api_encoder:decode(B) of + {Type, Encoding} -> + Encoding; + _ -> erlang:error({bad_address_encoding, Type, S}) + catch _:_ -> + erlang:error({bad_address_encoding, Type, S}) + end. diff --git a/test/asm_code/all_instructions.fate b/test/asm_code/all_instructions.fate index 82ca2e4..e585471 100644 --- a/test/asm_code/all_instructions.fate +++ b/test/asm_code/all_instructions.fate @@ -112,7 +112,7 @@ FUNCTION foo () : {tuple, []} ADDR_TO_STR a arg216 - STR_REVERSE a174 @nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv + STR_REVERSE a174 @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv INT_TO_ADDR arg127 var207 @@ -180,11 +180,11 @@ FUNCTION foo () : {tuple, []} LOG3 arg255 arg15 arg211 var139 arg44 - LOG4 @nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv a247 a 9 a38 a + LOG4 @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv a247 a 9 a38 a DEACTIVATE - SPEND @nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv var136 + SPEND @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv var136 ORACLE_REGISTER arg29 48 ((| 5 | 2 | (1, "foo", ()) |)) arg65 { <> => false} <> diff --git a/test/asm_code/immediates.fate b/test/asm_code/immediates.fate index 3efcc1a..d0b6445 100644 --- a/test/asm_code/immediates.fate +++ b/test/asm_code/immediates.fate @@ -66,7 +66,7 @@ FUNCTION tuple() : {tuple, [integer, boolean, string, {tuple, [integer, integer] FUNCTION address() : address - RETURNR #deadbeef + RETURNR @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv ;; Option(integer) = NONE | SOME(integer) FUNCTION variant_none() : {variant, [{tuple, []}, {tuple, [integer]}]}