diff --git a/rebar.lock b/rebar.lock index a3392b5..83e3967 100644 --- a/rebar.lock +++ b/rebar.lock @@ -11,7 +11,7 @@ {git,"https://github.com/aeternity/erl-base58.git", {ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}}, 2}, - {<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},1}, + {<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0}, {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}, {<<"jsx">>, {git,"https://github.com/talentdeficit/jsx.git", diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index e222f8d..54da3f8 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -136,7 +136,7 @@ on_current_scope(Env = #env{ namespace = NS, scopes = Scopes }, Fun) -> Env#env{ scopes = Scopes#{ NS => Fun(Scope) } }. -spec on_scopes(env(), fun((scope()) -> scope())) -> env(). -on_scopes(Env = #env{ namespace = NS, scopes = Scopes }, Fun) -> +on_scopes(Env = #env{ scopes = Scopes }, Fun) -> Env#env{ scopes = maps:map(fun(_, Scope) -> Fun(Scope) end, Scopes) }. -spec bind_var(aeso_syntax:id(), type(), env()) -> env(). @@ -401,7 +401,7 @@ global_env() -> [{"spend", StateFun([Address, Int], Unit)}, %% Chain environment {"balance", Fun1(Address, Int)}, - {"block_hash", Fun1(Int, Int)}, + {"block_hash", Fun1(Int, Option(Hash))}, {"coinbase", Address}, {"timestamp", Int}, {"block_height", Int}, diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index 5542354..c495d2f 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -141,7 +141,7 @@ ast_body(?qid_app([Con, "Chain", "event"], [Event], _, _), Icode = #{ contract_n ast_body(?qid_app(["Chain", "balance"], [Address], _, _), Icode) -> #prim_balance{ address = ast_body(Address, Icode) }; ast_body(?qid_app(["Chain", "block_hash"], [Height], _, _), Icode) -> - #prim_block_hash{ height = ast_body(Height, Icode) }; + builtin_call(block_hash, [ast_body(Height, Icode)]); ast_body(?qid_app(["Call", "gas_left"], [], _, _), _Icode) -> prim_gas_left; ast_body({qid, _, ["Contract", "address"]}, _Icode) -> prim_contract_address; diff --git a/src/aeso_builtins.erl b/src/aeso_builtins.erl index 93c1c57..b913db9 100644 --- a/src/aeso_builtins.erl +++ b/src/aeso_builtins.erl @@ -130,6 +130,7 @@ builtin_function(BF) -> case BF of {event, EventT} -> bfun(BF, builtin_event(EventT)); abort -> bfun(BF, builtin_abort()); + block_hash -> bfun(BF, builtin_block_hash()); require -> bfun(BF, builtin_require()); {map_lookup, Type} -> bfun(BF, builtin_map_lookup(Type)); map_put -> bfun(BF, builtin_map_put()); @@ -211,6 +212,12 @@ builtin_abort() -> A(?REVERT)]}, %% Stack: 0,Ptr {tuple,[]}}. +builtin_block_hash() -> + {[{"height", word}], + ?LET(hash, #prim_block_hash{ height = ?V(height)}, + {ifte, ?EQ(hash, 0), option_none(), option_some(?V(hash))}), + aeso_icode:option_typerep(word)}. + builtin_require() -> {[{"c", word}, {"msg", string}], {ifte, ?V(c), {tuple, []}, ?call(abort, [?V(msg)])}, diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index a07b955..d355570 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -288,25 +288,40 @@ to_sophia_value(_, _, revert, Data, _Options) -> end; to_sophia_value(ContractString, FunName, ok, Data, Options) -> try - #{ typed_ast := TypedAst, - type_env := TypeEnv, - icode := Icode } = string_to_code(ContractString, Options), + Code = string_to_code(ContractString, Options), + #{ typed_ast := TypedAst, type_env := TypeEnv} = Code, {ok, _, Type0} = get_decode_type(FunName, TypedAst), Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]), - VmType = aeso_ast_to_icode:ast_typerep(Type, Icode), - case aeb_heap:from_binary(VmType, Data) of - {ok, VmValue} -> - try - {ok, aeso_vm_decode:from_aevm(VmType, Type, VmValue)} - catch throw:cannot_translate_to_sophia -> - Type0Str = prettypr:format(aeso_pretty:type(Type0)), - {error, join_errors("Translation error", [lists:flatten(io_lib:format("Cannot translate VM value ~p\n of type ~p\n to Sophia type ~s\n", - [Data, VmType, Type0Str]))], - fun (E) -> E end)} + + case proplists:get_value(backend, Options, aevm) of + aevm -> + Icode = maps:get(icode, Code), + VmType = aeso_ast_to_icode:ast_typerep(Type, Icode), + case aeb_heap:from_binary(VmType, Data) of + {ok, VmValue} -> + try + {ok, aeso_vm_decode:from_aevm(VmType, Type, VmValue)} + catch throw:cannot_translate_to_sophia -> + Type0Str = prettypr:format(aeso_pretty:type(Type0)), + {error, join_errors("Translation error", [lists:flatten(io_lib:format("Cannot translate VM value ~p\n of type ~p\n to Sophia type ~s\n", + [Data, VmType, Type0Str]))], + fun (E) -> E end)} + end; + {error, _Err} -> + {error, join_errors("Decode errors", [lists:flatten(io_lib:format("Failed to decode binary at type ~p", [VmType]))], + fun(E) -> E end)} end; - {error, _Err} -> - {error, join_errors("Decode errors", [lists:flatten(io_lib:format("Failed to decode binary at type ~p", [VmType]))], - fun(E) -> E end)} + fate -> + try + {ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))} + catch throw:cannot_translate_to_sophia -> + {error, join_errors("Translation error", + [lists:flatten(io_lib:format("Cannot translate fate value ~p\n of Sophia type ~s\n", + [aeb_fate_encoding:deserialize(Data), Type]))], + fun (E) -> E end)}; + _:R -> + {error, iolist_to_binary(io_lib:format("Decode error ~p: ~p\n", [R, erlang:get_stacktrace()]))} + end end catch error:{parse_errors, Errors} -> diff --git a/test/contracts/environment.aes b/test/contracts/environment.aes index 3f7f721..085b683 100644 --- a/test/contracts/environment.aes +++ b/test/contracts/environment.aes @@ -50,7 +50,7 @@ contract Environment = function get_balance(acct : address) : int = Chain.balance(acct) // Block hash - function block_hash(height : int) : int = Chain.block_hash(height) + function block_hash(height : int) : option(hash) = Chain.block_hash(height) // Coinbase function coinbase() : address = Chain.coinbase