diff --git a/src/aeso_ast_infer_types.erl b/src/aeso_ast_infer_types.erl index ae6fb16..a3455eb 100644 --- a/src/aeso_ast_infer_types.erl +++ b/src/aeso_ast_infer_types.erl @@ -380,7 +380,8 @@ global_env() -> {"RelativeTTL", Fun1(Int, TTL)}, {"FixedTTL", Fun1(Int, TTL)}, %% Abort - {"abort", Fun1(String, A)}]) + {"abort", Fun1(String, A)}, + {"require", Fun([Bool, String], A)}]) , types = MkDefs( [{"int", 0}, {"bool", 0}, {"char", 0}, {"string", 0}, {"address", 0}, {"hash", {[], {alias_t, Bytes(32)}}}, diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index e7cb013..6948b3d 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -170,7 +170,7 @@ builtins() -> MkName = fun(NS, Fun) -> list_to_atom(string:to_lower(string:join(NS ++ [Fun], "_"))) end, - Scopes = [{[], [{"abort", 1}]}, + Scopes = [{[], [{"abort", 1}, {"require", 2}]}, {["Chain"], [{"spend", 2}, {"balance", 1}, {"block_hash", 1}, {"coinbase", none}, {"timestamp", none}, {"block_height", none}, {"difficulty", none}, {"gas_limit", none}]}, @@ -765,6 +765,8 @@ op_builtins() -> bits_difference, int_to_str, address_to_str, crypto_ecverify, crypto_ecverify_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b]. +builtin_to_fcode(require, [Cond, Msg]) -> + make_if(Cond, {tuple, []}, {builtin, abort, [Msg]}); builtin_to_fcode(map_delete, [Key, Map]) -> {op, map_delete, [Map, Key]}; builtin_to_fcode(map_member, [Key, Map]) -> diff --git a/src/aeso_ast_to_icode.erl b/src/aeso_ast_to_icode.erl index d296f1a..24f9c05 100644 --- a/src/aeso_ast_to_icode.erl +++ b/src/aeso_ast_to_icode.erl @@ -174,6 +174,8 @@ ast_body({qid, _, [Con, "put"]}, #{ contract_name := Con }) -> %% Abort ast_body(?id_app("abort", [String], _, _), Icode) -> builtin_call(abort, [ast_body(String, Icode)]); +ast_body(?id_app("require", [Bool, String], _, _), Icode) -> + builtin_call(require, [ast_body(Bool, Icode), ast_body(String, Icode)]); %% Authentication ast_body({qid, _, ["Auth", "tx_hash"]}, _Icode) -> diff --git a/src/aeso_builtins.erl b/src/aeso_builtins.erl index b94cb79..bd4010c 100644 --- a/src/aeso_builtins.erl +++ b/src/aeso_builtins.erl @@ -45,6 +45,7 @@ builtin_deps1({baseX_int, X}) -> [{baseX_int_pad, X}]; builtin_deps1({baseX_int_pad, X}) -> [{baseX_int_encode, X}]; builtin_deps1({baseX_int_encode, X}) -> [{baseX_int_encode_, X}, {baseX_tab, X}, {baseX_digits, X}]; builtin_deps1(string_reverse) -> [string_reverse_]; +builtin_deps1(require) -> [abort]; builtin_deps1(_) -> []. dep_closure(Deps) -> @@ -131,6 +132,7 @@ builtin_function(BF) -> case BF of {event, EventT} -> bfun(BF, builtin_event(EventT)); abort -> bfun(BF, builtin_abort()); + require -> bfun(BF, builtin_require()); {map_lookup, Type} -> bfun(BF, builtin_map_lookup(Type)); map_put -> bfun(BF, builtin_map_put()); map_delete -> bfun(BF, builtin_map_delete()); @@ -201,6 +203,11 @@ builtin_abort() -> A(?REVERT)]}, %% Stack: 0,Ptr {tuple,[]}}. +builtin_require() -> + {[{"c", word}, {"msg", string}], + {ifte, ?V(c), {tuple, []}, ?call(abort, [?V(msg)])}, + {tuple, []}}. + %% Map primitives builtin_map_lookup(Type) -> Ret = aeso_icode:option_typerep(Type), diff --git a/test/contracts/aeproof.aes b/test/contracts/aeproof.aes index 75006eb..53402b1 100644 --- a/test/contracts/aeproof.aes +++ b/test/contracts/aeproof.aes @@ -104,10 +104,10 @@ contract AEProof = proofsByOwner : map(address, array(uint)) } function notarize(document:string, comment:string, ipfsHash:hash) = - let _ = require(aetoken.balanceOf(caller()) > 0) + let _ = require(aetoken.balanceOf(caller()) > 0, "false") let proofHash: uint = calculateHash(document) let proof : proof = Map.get_(proofHash, state().proofs) - let _ = require(proof.owner == #0) + let _ = require(proof.owner == #0, "false") let proof' : proof = proof { owner = caller() , timestamp = block().timestamp , proofBlock = block().height @@ -124,12 +124,12 @@ contract AEProof = function getProof(document) : proof = let calcHash = calculateHash(document) let proof = Map.get_(calcHash, state().proofs) - let _ = require(proof.owner != #0) + let _ = require(proof.owner != #0, "false") proof function getProofByHash(hash: uint) : proof = let proof = Map.get_(hash, state().proofs) - let _ = require(proof.owner != #0) + let _ = require(proof.owner != #0, "false") proof @@ -141,5 +141,3 @@ contract AEProof = function getProofsByOwner(owner: address): array(uint) = Map.get(owner, state()) - function require(x : bool) : unit = if(x) () else abort("false") - diff --git a/test/contracts/basic_auth.aes b/test/contracts/basic_auth.aes index 641c01e..3e2647f 100644 --- a/test/contracts/basic_auth.aes +++ b/test/contracts/basic_auth.aes @@ -15,5 +15,3 @@ contract BasicAuth = function to_sign(h : hash, n : int) = Crypto.blake2b((h, n)) - private function require(b : bool, err : string) = - if(!b) abort(err) diff --git a/test/contracts/bitcoin_auth.aes b/test/contracts/bitcoin_auth.aes index ba60c31..9d421c8 100644 --- a/test/contracts/bitcoin_auth.aes +++ b/test/contracts/bitcoin_auth.aes @@ -14,5 +14,3 @@ contract BitcoinAuth = function to_sign(h : hash, n : int) : hash = Crypto.blake2b((h, n)) - private function require(b : bool, err : string) = - if(!b) abort(err) diff --git a/test/contracts/dutch_auction.aes b/test/contracts/dutch_auction.aes index deca3ef..a9c5db0 100644 --- a/test/contracts/dutch_auction.aes +++ b/test/contracts/dutch_auction.aes @@ -15,9 +15,6 @@ contract DutchAuction = Chain.spend(to, amount) total - amount - private function require(b : bool, err : string) = - if(!b) abort(err) - // TTL set by user on posting contract, typically (start - end ) div dec public function init(beneficiary, start, decrease) : state = require(start > 0 && decrease > 0, "bad args") diff --git a/test/contracts/erc20_token.aes b/test/contracts/erc20_token.aes index f2c5cca..517b9f4 100644 --- a/test/contracts/erc20_token.aes +++ b/test/contracts/erc20_token.aes @@ -77,9 +77,6 @@ contract ERC20Token = put( state{approval_log = e :: state.approval_log }) e - private function require(b : bool, err : string) = - if(!b) abort(err) - private function sub(_a : int, _b : int) : int = require(_b =< _a, "Error") _a - _b diff --git a/test/contracts/fundme.aes b/test/contracts/fundme.aes index 08f5d69..abae348 100644 --- a/test/contracts/fundme.aes +++ b/test/contracts/fundme.aes @@ -12,9 +12,6 @@ contract FundMe = deadline : int, goal : int } - private function require(b : bool, err : string) = - if(!b) abort(err) - private stateful function spend(args : spend_args) = Chain.spend(args.recipient, args.amount) diff --git a/test/contracts/oracles.aes b/test/contracts/oracles.aes index e6e44b4..97561ff 100644 --- a/test/contracts/oracles.aes +++ b/test/contracts/oracles.aes @@ -108,5 +108,3 @@ contract Oracles = Oracle.respond(o, q, Answer(question, "magic", 1337), signature = sig) Oracle.get_answer(o, q) - private function require(b : bool, err : string) = - if(!b) abort(err) diff --git a/test/contracts/oracles_gas.aes b/test/contracts/oracles_gas.aes index 7e75a67..87c8b28 100644 --- a/test/contracts/oracles_gas.aes +++ b/test/contracts/oracles_gas.aes @@ -20,5 +20,3 @@ contract OraclesGas = Oracle.respond(o, q, answer) () - private function require(b : bool, err : string) = - if(!b) abort(err) diff --git a/test/contracts/oracles_no_vm.aes b/test/contracts/oracles_no_vm.aes index ad32066..b0ba9ac 100644 --- a/test/contracts/oracles_no_vm.aes +++ b/test/contracts/oracles_no_vm.aes @@ -33,5 +33,3 @@ contract Oracles = q : query_id) : option(answer_t) = Oracle.get_answer(o, q) - private function require(b : bool, err : string) = - if(!b) abort(err) diff --git a/test/contracts/variant_types.aes b/test/contracts/variant_types.aes index 59079c2..3d84161 100644 --- a/test/contracts/variant_types.aes +++ b/test/contracts/variant_types.aes @@ -9,8 +9,6 @@ contract VariantTypes = function init() = Stopped - function require(b) = if(!b) abort("required") - stateful function start(bal : int) = switch(state) Stopped => put(Started({owner = Call.caller, balance = bal, color = Grey(0)})) @@ -18,7 +16,7 @@ contract VariantTypes = stateful function stop() = switch(state) Started(st) => - require(Call.caller == st.owner) + require(Call.caller == st.owner, "required") put(Stopped) st.balance