From e75336486ece21263e11a5ad192279615182c9fc Mon Sep 17 00:00:00 2001 From: Hans Svensson Date: Wed, 14 Aug 2019 13:37:17 +0200 Subject: [PATCH] Track payable (and private) in FATE/AEVM type info Privateness is only tracked for FATE. --- src/aeb_aevm_abi.erl | 104 ++++++++++++++++++++++++++++-------------- src/aeb_fate_abi.erl | 2 +- src/aeb_fate_asm.erl | 4 +- src/aeb_fate_code.erl | 63 ++++++++++++++++--------- 4 files changed, 116 insertions(+), 57 deletions(-) diff --git a/src/aeb_aevm_abi.erl b/src/aeb_aevm_abi.erl index 6b3bfdf..da0a159 100644 --- a/src/aeb_aevm_abi.erl +++ b/src/aeb_aevm_abi.erl @@ -11,14 +11,15 @@ -define(HASH_SIZE, 32). -export([ create_calldata/4 - , check_calldata/2 - , function_type_info/3 + , check_calldata/3 + , function_type_info/4 , function_type_hash/3 , arg_typerep_from_function/2 , type_hash_from_function_name/2 , typereps_from_type_hash/2 , function_name_from_type_hash/2 , get_function_hash_from_calldata/1 + , is_payable/2 , abi_version/0 ]). @@ -27,6 +28,7 @@ -type typerep() :: aeb_aevm_data:type(). -type function_type_info() :: { FunctionHash :: hash() , FunctionName :: function_name() + , Payable :: boolean() , ArgType :: binary() %% binary typerep , OutType :: binary() %% binary typerep }. @@ -51,30 +53,40 @@ create_calldata(FunName, Args, ArgTypes0, RetType) -> Data = aeb_heap:to_binary({TypeHashInt, list_to_tuple(Args)}), {ok, Data}. --spec check_calldata(binary(), type_info()) -> +-spec check_calldata(binary(), type_info(), boolean()) -> {'ok', typerep(), typerep()} | {'error', atom()}. -check_calldata(CallData, TypeInfo) -> +check_calldata(CallData, TypeInfo, CheckPayable) -> %% The first element of the CallData should be the function name case get_function_hash_from_calldata(CallData) of {ok, Hash} -> - case typereps_from_type_hash(Hash, TypeInfo) of - {ok, ArgType, OutType} -> - try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of - {ok, _Something} -> - {ok, {tuple, [word, ArgType]}, OutType}; - {error, _} -> - {error, bad_call_data} - catch - _T:_E -> - {error, bad_call_data} - end; - {error, _} -> - {error, unknown_function} - end; + check_calldata(Hash, CallData, TypeInfo, CheckPayable); {error, _What} -> {error, bad_call_data} end. +check_calldata(Hash, CallData, TypeInfo, true) -> + case is_payable(Hash, TypeInfo) of + {ok, true} -> check_calldata(Hash, CallData, TypeInfo, false); + {ok, false} -> {error, function_is_not_payable}; + Err = {error, _} -> Err + end; +check_calldata(Hash, CallData, TypeInfo, false) -> + case typereps_from_type_hash(Hash, TypeInfo) of + {ok, ArgType, OutType} -> + try aeb_heap:from_binary({tuple, [word, ArgType]}, CallData) of + {ok, _Something} -> + {ok, {tuple, [word, ArgType]}, OutType}; + {error, _} -> + {error, bad_call_data} + catch + _T:_E -> + {error, bad_call_data} + end; + {error, _} -> + {error, unknown_function} + end. + + -spec get_function_hash_from_calldata(CallData::binary()) -> {ok, binary()} | {error, term()}. get_function_hash_from_calldata(CallData) -> @@ -86,12 +98,13 @@ get_function_hash_from_calldata(CallData) -> %%%=================================================================== %%% Handle type info from contract meta data --spec function_type_info(function_name(), [typerep()], typerep()) -> +-spec function_type_info(function_name(), boolean(), [typerep()], typerep()) -> function_type_info(). -function_type_info(Name, ArgTypes, OutType) -> +function_type_info(Name, Payable, ArgTypes, OutType) -> ArgType = {tuple, ArgTypes}, { function_type_hash(Name, ArgType, OutType) , Name + , Payable , aeb_heap:to_binary(ArgType) , aeb_heap:to_binary(OutType) }. @@ -110,35 +123,46 @@ function_type_hash(Name, ArgType, OutType) when is_binary(Name) -> {'ok', typerep()} | {'error', 'bad_type_data' | 'unknown_function'}. arg_typerep_from_function(Function, TypeInfo) -> case lists:keyfind(Function, 2, TypeInfo) of - {_TypeHash, Function, ArgTypeBin,_OutTypeBin} -> - case aeb_heap:from_binary(typerep, ArgTypeBin) of - {ok, ArgType} -> {ok, ArgType}; - {error,_} -> {error, bad_type_data} - end; + {_TypeHash, Function, ArgTypeBin, _OutTypeBin} -> + arg_typerep_from_type_binary(ArgTypeBin); + {_TypeHash, Function, _Payable, ArgTypeBin, _OutTypeBin} -> + arg_typerep_from_type_binary(ArgTypeBin); false -> {error, unknown_function} end. +arg_typerep_from_type_binary(ArgTBin) -> + case aeb_heap:from_binary(typerep, ArgTBin) of + {ok, ArgT} -> {ok, ArgT}; + {error,_} -> {error, bad_type_data} + end. + -spec typereps_from_type_hash(hash(), type_info()) -> {'ok', typerep(), typerep()} | {'error', 'bad_type_data' | 'unknown_function'}. typereps_from_type_hash(TypeHash, TypeInfo) -> case lists:keyfind(TypeHash, 1, TypeInfo) of - {TypeHash,_Function, ArgTypeBin, OutTypeBin} -> - case {aeb_heap:from_binary(typerep, ArgTypeBin), - aeb_heap:from_binary(typerep, OutTypeBin)} of - {{ok, ArgType}, {ok, OutType}} -> {ok, ArgType, OutType}; - {_, _} -> {error, bad_type_data} - end; + {TypeHash, _Function, ArgTypeBin, OutTypeBin} -> + typereps_from_type_binaries(ArgTypeBin, OutTypeBin); + {TypeHash, _Function, _Payable, ArgTypeBin, OutTypeBin} -> + typereps_from_type_binaries(ArgTypeBin, OutTypeBin); false -> {error, unknown_function} end. +typereps_from_type_binaries(ArgTBin, OutTBin) -> + case {aeb_heap:from_binary(typerep, ArgTBin), aeb_heap:from_binary(typerep, OutTBin)} of + {{ok, ArgT}, {ok, OutT}} -> {ok, ArgT, OutT}; + {_, _} -> {error, bad_type_data} + end. + -spec function_name_from_type_hash(hash(), type_info()) -> {'ok', function_name()} | {'error', 'unknown_function'}. function_name_from_type_hash(TypeHash, TypeInfo) -> case lists:keyfind(TypeHash, 1, TypeInfo) of - {TypeHash, Function,_ArgTypeBin,_OutTypeBin} -> + {TypeHash, Function, _ArgTypeBin, _OutTypeBin} -> + {ok, Function}; + {TypeHash, Function, _Payable, _ArgTypeBin, _OutTypeBin} -> {ok, Function}; false -> {error, unknown_function} @@ -149,8 +173,22 @@ function_name_from_type_hash(TypeHash, TypeInfo) -> | {'error', 'unknown_function'}. type_hash_from_function_name(Name, TypeInfo) -> case lists:keyfind(Name, 2, TypeInfo) of - {TypeHash, Name,_ArgTypeBin,_OutTypeBin} -> + {TypeHash, Name, _ArgTypeBin, _OutTypeBin} -> + {ok, TypeHash}; + {TypeHash, Name, _Payable, _ArgTypeBin, _OutTypeBin} -> {ok, TypeHash}; false -> {error, unknown_function} end. + +-spec is_payable(hash(), type_info()) -> {ok, boolean()} | {error, 'unknown_function'}. +is_payable(TypeHash, TypeInfo) -> + case lists:keyfind(TypeHash, 1, TypeInfo) of + {TypeHash, _Function, _ArgTypeBin, _OutTypeBin} -> + {ok, true}; + {TypeHash, _Function, Payable, _ArgTypeBin, _OutTypeBin} -> + {ok, Payable}; + false -> + {error, unknown_function} + end. + diff --git a/src/aeb_fate_abi.erl b/src/aeb_fate_abi.erl index b54227d..a7e89dd 100644 --- a/src/aeb_fate_abi.erl +++ b/src/aeb_fate_abi.erl @@ -72,6 +72,6 @@ get_function_type_from_function_hash(SymbolHash, FateCode) -> case maps:get(SymbolHash, Functions, undefined) of undefined -> {error, no_function_matching_function_hash}; - {{ArgTypes, RetType}, _Code} -> + {_Attrs, {ArgTypes, RetType}, _Code} -> {ok, ArgTypes, RetType} end. diff --git a/src/aeb_fate_asm.erl b/src/aeb_fate_asm.erl index 9803909..f6435a7 100644 --- a/src/aeb_fate_asm.erl +++ b/src/aeb_fate_asm.erl @@ -153,7 +153,7 @@ format_functions(Functions, Symbols) -> lists:sort(maps:to_list(CodeMap)), Symbols) || - {Name, {Sig, CodeMap}} <- maps:to_list(Functions)]. + {Name, {_Attrs, Sig, CodeMap}} <- maps:to_list(Functions)]. format(Name, Sig, BBs, Symbols) -> @@ -484,7 +484,7 @@ insert_fun({NameString, ArgType, RetType}, Code, #{ fate_code := FateCode {FateCode1, Id} = aeb_fate_code:insert_symbol(Name, FateCode), BodyByteCode = aeb_fate_code:serialize_code(lists:reverse(Code)), SigByteCode = aeb_fate_code:serialize_signature({ArgType, RetType}), - FunByteCode = [?FUNCTION, Id, SigByteCode, BodyByteCode], + FunByteCode = [?FUNCTION, Id, aeb_fate_encoding:serialize(0), SigByteCode, BodyByteCode], Env#{ functions => Funs#{ Id => FunByteCode } , fate_code => FateCode1}. diff --git a/src/aeb_fate_code.erl b/src/aeb_fate_code.erl index 73c1ea1..829a50d 100644 --- a/src/aeb_fate_code.erl +++ b/src/aeb_fate_code.erl @@ -11,7 +11,7 @@ , deserialize/1 , functions/1 , insert_annotation/4 - , insert_fun/4 + , insert_fun/5 , insert_symbol/2 , new/0 , serialize/1 @@ -72,9 +72,9 @@ symbol_identifier(Bin) -> {ok, <> } = eblake2:blake2b(?HASH_BYTES, Bin), X. -insert_fun(Name, {ArgType, RetType}, #{} = BBs, FCode) -> +insert_fun(Name, Attrs, {ArgType, RetType}, #{} = BBs, FCode) -> {F1, ID} = insert_symbol(Name, FCode), - update_functions(F1, #{ID => {{ArgType, RetType}, BBs}}). + update_functions(F1, #{ID => {Attrs, {ArgType, RetType}, BBs}}). insert_symbol(Name, #fcode{ symbols = Syms } = F) -> ID = symbol_identifier(Name), @@ -128,10 +128,17 @@ to_hexstring(ByteList) -> serialize_functions(#fcode{ functions = Functions }) -> %% Sort the functions on name to get a canonical serialisation. iolist_to_binary( - lists:foldr(fun({Id, {Sig, C}}, Acc) -> - [[?FUNCTION, Id, serialize_signature(Sig), serialize_bbs(C)] | Acc] + lists:foldr(fun({Id, {Attrs, Sig, C}}, Acc) -> + [[?FUNCTION, Id, serialize_attributes(Attrs), serialize_signature(Sig), serialize_bbs(C)] | Acc] end, [], lists:sort(maps:to_list(Functions)))). +serialize_attributes(Attrs) -> + AttrVal = lists:sum([ attr_value(Attr) || Attr <- Attrs ]), + aeb_fate_encoding:serialize(?MAKE_FATE_INTEGER(AttrVal)). + +attr_value(private) -> 1; +attr_value(payable) -> 2. + serialize_signature({Args, RetType}) -> [aeb_fate_encoding:serialize_type({tuple, Args}) | aeb_fate_encoding:serialize_type(RetType)]. @@ -139,7 +146,7 @@ serialize_signature({Args, RetType}) -> serialize_symbol_table(#fcode{ symbols = Symbols }) -> aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)). -serialize_annotations(#fcode{ annotations = Annotations}) -> +serialize_annotations(#fcode{ annotations = Annotations }) -> aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)). serialize_bbs(#{} = BBs) -> @@ -166,8 +173,8 @@ serialize_op(Op) -> sanity_check(#fcode{ functions = Funs }) -> _ = [ case Def of - {_, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs); - _ -> error({illegal_function_id, Id}) + {_, _, BBs} when byte_size(Id) == 4 -> sanity_check_bbs(BBs); + _ -> error({illegal_function_id, Id}) end || {Id, Def} <- maps:to_list(Funs) ], ok. @@ -303,33 +310,35 @@ deserialize_functions(<>, , bb := 0 , current_bb_code := [] } = Env) -> - {Sig, Rest2} = deserialize_signature(Rest), - Env2 = Env#{function => {<>, Sig}}, - deserialize_functions(Rest2, Env2); + {Attrs, Rest2} = deserialize_attributes(Rest), + {Sig, Rest3} = deserialize_signature(Rest2), + Env2 = Env#{function => {<>, Attrs, Sig}}, + deserialize_functions(Rest3, Env2); deserialize_functions(<>, - #{ function := {F, Sig} + #{ function := {F, Attrs, Sig} , bb := BB , current_bb_code := Code , code := Program , functions := Funs} = Env) -> - {NewSig, Rest2} = deserialize_signature(Rest), + {NewAttrs, Rest2} = deserialize_attributes(Rest), + {NewSig, Rest3} = deserialize_signature(Rest2), case Code of [] -> Env2 = Env#{ bb => 0 , current_bb_code => [] - , function => {<>, NewSig} + , function => {<>, NewAttrs, NewSig} , code => #{} - , functions => Funs#{F => {Sig, Program}}}, - deserialize_functions(Rest2, Env2); + , functions => Funs#{F => {Attrs, Sig, Program}}}, + deserialize_functions(Rest3, Env2); _ -> Env2 = Env#{ bb => 0 , current_bb_code => [] - , function => {<>, NewSig} + , function => {<>, NewAttrs, NewSig} , code => #{} , functions => - Funs#{F => {Sig, + Funs#{F => {Attrs, Sig, Program#{ BB => lists:reverse(Code)}}}}, - deserialize_functions(Rest2, Env2) + deserialize_functions(Rest3, Env2) end; deserialize_functions(<<_Op:8, _Rest/binary>>, #{ function := none }) -> @@ -351,7 +360,7 @@ deserialize_functions(<>, deserialize_functions(<<>>, #{ function := none , functions := Funs}) -> Funs; -deserialize_functions(<<>>, #{ function := {F, Sig} +deserialize_functions(<<>>, #{ function := {F, Attrs, Sig} , bb := BB , current_bb_code := Code , code := Program @@ -361,7 +370,7 @@ deserialize_functions(<<>>, #{ function := {F, Sig} [] -> Program; _ -> Program#{ BB => lists:reverse(Code)} end, - Funs#{F => {Sig, FunctionCode}}. + Funs#{F => {Attrs, Sig, FunctionCode}}. deserialize_op(Op, Rest, Code) -> OpName = aeb_fate_opcodes:mnemonic(Op), @@ -399,6 +408,18 @@ deserialize_n_args(N, < + {AttrVal, Rest} = aeb_fate_encoding:deserialize_one(Binary), + Attrs = [ attr(AVal) || AVal <- attr_vals(1, AttrVal) ], + {lists:sort(Attrs), Rest}. + +attr_vals(_, 0) -> []; +attr_vals(X, N) when N rem 2 == 0 -> attr_vals(X + 1, N div 2); +attr_vals(X, N) -> [X | attr_vals(X + 1, N div 2)]. + +attr(1) -> private; +attr(2) -> payable. + deserialize_signature(Binary) -> {{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary), {RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),