From c27031f67dfaa00edecc75d222ebe40b8847342a Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Wed, 20 Apr 2022 16:01:31 +0200 Subject: [PATCH 1/3] add print builtin equivalent of nomic's console.log --- vyper/builtin_functions/functions.py | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/vyper/builtin_functions/functions.py b/vyper/builtin_functions/functions.py index 280532ceb4..fe990a1e42 100644 --- a/vyper/builtin_functions/functions.py +++ b/vyper/builtin_functions/functions.py @@ -36,6 +36,7 @@ SArrayType, StringType, TupleType, + get_type_for_exact_size, is_base_type, is_bytes_m_type, parse_integer_typeinfo, @@ -86,6 +87,7 @@ DECIMAL_DIVISOR, MemoryPositions, SizeLimits, + abi_method_id, bytes_to_int, fourbytes_to_int, keccak256, @@ -1867,6 +1869,38 @@ def build_IR(self, expr, args, kwargs, context): return IRnode("~empty", typ=output_type) +class Print(_SimpleBuiltinFunction): + _id = "print" + _inputs = [("arg", "*")] + + def fetch_call_return(self, node): + validate_call_args(node, 1) + return None + + @validate_inputs + def build_IR(self, expr, args, kwargs, context): + args = [Expr(arg, context).ir_node for arg in expr.args] + args_tuple_t = TupleType([x.typ for x in args]) + args_as_tuple = IRnode.from_list(["multi"] + [x for x in args], typ=args_tuple_t) + args_abi_t = args_tuple_t.abi_type + sig = "log" + "(" + ",".join([arg.typ.abi_type.selector_name() for arg in args]) + ")" + method_id = abi_method_id(sig) + + buflen = 32 + args_abi_t.size_bound() + + # 32 bytes extra space for the method id + buf = context.new_internal_variable(get_type_for_exact_size(buflen)) + + ret = ["seq"] + ret.append(["mstore", buf, method_id]) + encode = abi_encode(buf + 32, args_as_tuple, context, buflen, returns_len=True) + + CONSOLE_ADDRESS = 0x000000000000000000636F6E736F6C652E6C6F67 + ret.append(["staticcall", "gas", CONSOLE_ADDRESS, buf + 28, encode, 0, 0]) + + return IRnode.from_list(ret, annotation="print:" + sig) + + class ABIEncode(_SimpleBuiltinFunction): _id = "_abi_encode" # TODO prettier to rename this to abi.encode # signature: *, ensure_tuple= -> Bytes[] @@ -2046,6 +2080,7 @@ def build_IR(self, expr, context): STMT_DISPATCH_TABLE = { "send": Send(), + "print": Print(), "selfdestruct": SelfDestruct(), "raw_call": RawCall(), "raw_log": RawLog(), From 478af98207565b9bc7ccb40d30847b81cba44d75 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Wed, 20 Apr 2022 22:58:48 +0200 Subject: [PATCH 2/3] add a user warning when print is used --- vyper/ast/nodes.py | 8 +++++--- vyper/builtin_functions/functions.py | 9 +++++++++ vyper/utils.py | 5 +++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index 8389f1e612..0c98871a7a 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -331,8 +331,12 @@ def __eq__(self, other): def __repr__(self): cls = type(self) class_repr = f"{cls.__module__}.{cls.__qualname__}" + return f"{class_repr}:\n{self.annotated_source}" - source_annotation = annotate_source_code( + @property + def _annotated_source(self): + # return source with context / line/col info + return annotate_source_code( self.full_source_code, self.lineno, self.col_offset, @@ -340,8 +344,6 @@ def __repr__(self): line_numbers=VYPER_ERROR_LINE_NUMBERS, ) - return f"{class_repr}:\n{source_annotation}" - @property def description(self): """ diff --git a/vyper/builtin_functions/functions.py b/vyper/builtin_functions/functions.py index fe990a1e42..b9ea7db7c0 100644 --- a/vyper/builtin_functions/functions.py +++ b/vyper/builtin_functions/functions.py @@ -91,6 +91,7 @@ bytes_to_int, fourbytes_to_int, keccak256, + vyper_warn, ) from .signatures import Optional, validate_inputs @@ -1873,7 +1874,13 @@ class Print(_SimpleBuiltinFunction): _id = "print" _inputs = [("arg", "*")] + _warned = False + def fetch_call_return(self, node): + if not self._warned: + vyper_warn("`print` should only be used for debugging!\n" + node._annotated_source) + self._warned = True + validate_call_args(node, 1) return None @@ -1883,6 +1890,7 @@ def build_IR(self, expr, args, kwargs, context): args_tuple_t = TupleType([x.typ for x in args]) args_as_tuple = IRnode.from_list(["multi"] + [x for x in args], typ=args_tuple_t) args_abi_t = args_tuple_t.abi_type + # create a signature like "log(uint256)" sig = "log" + "(" + ",".join([arg.typ.abi_type.selector_name() for arg in args]) + ")" method_id = abi_method_id(sig) @@ -1895,6 +1903,7 @@ def build_IR(self, expr, args, kwargs, context): ret.append(["mstore", buf, method_id]) encode = abi_encode(buf + 32, args_as_tuple, context, buflen, returns_len=True) + # debug address that tooling uses CONSOLE_ADDRESS = 0x000000000000000000636F6E736F6C652E6C6F67 ret.append(["staticcall", "gas", CONSOLE_ADDRESS, buf + 28, encode, 0, 0]) diff --git a/vyper/utils.py b/vyper/utils.py index 4df546cb66..6401bb7249 100644 --- a/vyper/utils.py +++ b/vyper/utils.py @@ -71,6 +71,11 @@ def trace(n=5, out=sys.stderr): print("END TRACE", file=out) +# print a warning +def vyper_warn(msg, prefix="Warning: ", file_=sys.stderr): + print(f"{prefix}{msg}", file=file_) + + # converts a signature like Func(bool,uint256,address) to its 4 byte method ID # TODO replace manual calculations in codebase with this def abi_method_id(method_sig): From 3b70ed70bfce877f1d2d84fe76d7d129192f1de4 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Thu, 21 Apr 2022 16:43:11 +0000 Subject: [PATCH 3/3] fix a typo --- vyper/ast/nodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index 0c98871a7a..d0a8d4110c 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -331,7 +331,7 @@ def __eq__(self, other): def __repr__(self): cls = type(self) class_repr = f"{cls.__module__}.{cls.__qualname__}" - return f"{class_repr}:\n{self.annotated_source}" + return f"{class_repr}:\n{self._annotated_source}" @property def _annotated_source(self):