def create_forwarder_to(expr, args, kwargs, context): value = kwargs['value'] if value != zero_value: enforce_units(value.typ, get_keyword(expr, 'value'), BaseType('uint256', {'wei': 1})) if context.is_constant(): raise ConstancyViolationException( f"Cannot make calls from {context.pp_constancy()}", expr, ) placeholder = context.new_placeholder(ByteArrayType(96)) kode = get_create_forwarder_to_bytecode() high = bytes_to_int(kode[:32]) low = bytes_to_int((kode + b'\x00' * 32)[47:79]) return LLLnode.from_list( [ 'seq', ['mstore', placeholder, high], ['mstore', ['add', placeholder, 27], ['mul', args[0], 2**96]], ['mstore', ['add', placeholder, 47], low], ['clamp_nonzero', ['create', value, placeholder, 96]], ], typ=BaseType('address'), pos=getpos(expr), add_gas_estimate=11000, )
def keccak256_helper(expr, to_hash, context): _check_byteslike(to_hash.typ, expr) # Can hash literals # TODO this is dead code. if isinstance(to_hash, bytes): return IRnode.from_list(bytes_to_int(keccak256(to_hash)), typ=BaseType("bytes32")) # Can hash bytes32 objects if is_base_type(to_hash.typ, "bytes32"): return IRnode.from_list( [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, to_hash], ["sha3", MemoryPositions.FREE_VAR_SPACE, 32], ], typ=BaseType("bytes32"), add_gas_estimate=_gas_bound(1), ) to_hash = ensure_in_memory(to_hash, context) with to_hash.cache_when_complex("buf") as (b1, to_hash): data = bytes_data_ptr(to_hash) len_ = get_bytearray_length(to_hash) return b1.resolve( IRnode.from_list( ["sha3", data, len_], typ="bytes32", annotation="keccak256", add_gas_estimate=_gas_bound(ceil(to_hash.typ.maxlen / 32)), ))
def _sha3(expr, args, kwargs, context): sub = args[0] # Can hash literals if isinstance(sub, bytes): return LLLnode.from_list(bytes_to_int(sha3(sub)), typ=BaseType('bytes32'), pos=getpos(expr)) # Can hash bytes32 objects if is_base_type(sub.typ, 'bytes32'): return LLLnode.from_list( ['seq', ['mstore', MemoryPositions.FREE_VAR_SPACE, sub], ['sha3', MemoryPositions.FREE_VAR_SPACE, 32]], typ=BaseType('bytes32'), pos=getpos(expr) ) # Copy the data to an in-memory array if sub.location == "memory": # If we are hashing a value in memory, no need to copy it, just hash in-place return LLLnode.from_list( ['with', '_sub', sub, ['sha3', ['add', '_sub', 32], ['mload', '_sub']]], typ=BaseType('bytes32'), pos=getpos(expr) ) elif sub.location == "storage": lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']], typ=BaseType('int128')) else: # This should never happen, but just left here for future compiler-writers. raise Exception("Unsupported location: %s" % sub.location) # pragma: no test placeholder = context.new_placeholder(sub.typ) placeholder_node = LLLnode.from_list(placeholder, typ=sub.typ, location='memory') copier = make_byte_array_copier(placeholder_node, LLLnode.from_list('_sub', typ=sub.typ, location=sub.location)) return LLLnode.from_list( ['with', '_sub', sub, ['seq', copier, ['sha3', ['add', placeholder, 32], lengetter]]], typ=BaseType('bytes32'), pos=getpos(expr) )
def keccak256_helper(expr, ir_arg, context): sub = ir_arg # TODO get rid of useless variable _check_byteslike(sub.typ, expr) # Can hash literals # TODO this is dead code. if isinstance(sub, bytes): return IRnode.from_list(bytes_to_int(keccak256(sub)), typ=BaseType("bytes32")) # Can hash bytes32 objects if is_base_type(sub.typ, "bytes32"): return IRnode.from_list( [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, sub], ["sha3", MemoryPositions.FREE_VAR_SPACE, 32], ], typ=BaseType("bytes32"), add_gas_estimate=_gas_bound(1), ) sub = ensure_in_memory(sub, context) return IRnode.from_list( [ "with", "_buf", sub, ["sha3", ["add", "_buf", 32], ["mload", "_buf"]], ], typ=BaseType("bytes32"), annotation="keccak256", add_gas_estimate=_gas_bound(ceil(sub.typ.maxlen / 32)), )
def fake_tx(): address = inject_tx( "0xf9035b808506fc23ac0083045f788080b903486103305660006109ac5260006109cc527f0100000000000000000000000000000000000000000000000000000000000000600035046109ec526000610a0c5260006109005260c06109ec51101515585760f86109ec51101561006e5760bf6109ec510336141558576001610a0c52610098565b60013560f76109ec51036020035260005160f66109ec510301361415585760f66109ec5103610a0c525b61022060016064818352015b36610a0c511015156100b557610291565b7f0100000000000000000000000000000000000000000000000000000000000000610a0c5135046109ec526109cc5160206109ac51026040015260016109ac51016109ac5260806109ec51101561013b5760016109cc5161044001526001610a0c516109cc5161046001376001610a0c5101610a0c5260216109cc51016109cc52610281565b60b86109ec5110156101d15760806109ec51036109cc51610440015260806109ec51036001610a0c51016109cc51610460013760816109ec5114156101ac5760807f01000000000000000000000000000000000000000000000000000000000000006001610a0c5101350410151558575b607f6109ec5103610a0c5101610a0c5260606109ec51036109cc51016109cc52610280565b60c06109ec51101561027d576001610a0c51013560b76109ec510360200352600051610a2c526038610a2c5110157f01000000000000000000000000000000000000000000000000000000000000006001610a0c5101350402155857610a2c516109cc516104400152610a2c5160b66109ec5103610a0c51016109cc516104600137610a2c5160b66109ec5103610a0c510101610a0c526020610a2c51016109cc51016109cc5261027f565bfe5b5b5b81516001018083528114156100a4575b5050601f6109ac511115155857602060206109ac5102016109005260206109005103610a0c5261022060016064818352015b6000610a0c5112156102d45761030a565b61090051610a0c516040015101610a0c51610900516104400301526020610a0c5103610a0c5281516001018083528114156102c3575b50506109cc516109005101610420526109cc5161090051016109005161044003f35b61000461033003610004600039610004610330036000f31b2d4f" ) assert vyper_utils.bytes_to_int( address) == vyper_utils.RLP_DECODER_ADDRESS return address
def pack_logging_topics(event_id, args, expected_topics, context): topics = [event_id] for pos, expected_topic in enumerate(expected_topics): typ = expected_topic.typ arg = args[pos] value = parse_expr(arg, context) if isinstance(typ, ByteArrayType) and ( isinstance(arg, ast.Str) or (isinstance(arg, ast.Name) and arg.id not in reserved_words)): if value.typ.maxlen > typ.maxlen: raise TypeMismatchException( "Topic input bytes are to big: %r %r" % (value.typ, typ)) if isinstance(arg, ast.Str): bytez, bytez_length = string_to_bytes(arg.s) if len(bytez) > 32: raise InvalidLiteralException( "Can only log a maximum of 32 bytes at a time.") topics.append( bytes_to_int(bytez + b'\x00' * (32 - bytez_length))) else: size = context.vars[arg.id].size topics.append(byte_array_to_num(value, arg, 'uint256', size)) else: value = unwrap_location(value) value = base_type_conversion(value, value.typ, typ) topics.append(value) return topics
def ann_assign(self): self.context.set_in_assignment(True) typ = parse_type(self.stmt.annotation, location='memory', custom_units=self.context.custom_units, custom_structs=self.context.structs) if isinstance(self.stmt.target, ast.Attribute): raise TypeMismatchException('May not set type for field %r' % self.stmt.target.attr, self.stmt) varname = self.stmt.target.id pos = self.context.new_variable(varname, typ) o = LLLnode.from_list('pass', typ=None, pos=pos) if self.stmt.value is not None: sub = Expr(self.stmt.value, self.context).lll_node # Disallow assignment to None if isinstance(sub.typ, NullType): raise InvalidLiteralException('Assignment to None is not allowed, use a default value or built-in `clear()`.', self.stmt) # If bytes[32] to bytes32 assignment rewrite sub as bytes32. if isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32 and isinstance(typ, BaseType) and typ.typ == 'bytes32': bytez, bytez_length = string_to_bytes(self.stmt.value.s) sub = LLLnode(bytes_to_int(bytez), typ=BaseType('bytes32'), pos=getpos(self.stmt)) self._check_valid_assign(sub) self._check_same_variable_assign(sub) variable_loc = LLLnode.from_list(pos, typ=typ, location='memory', pos=getpos(self.stmt)) o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt)) # o.pos = getpos(self.stmt) # TODO: Should this be here like in assign()? self.context.set_in_assignment(False) return o
def parse_AnnAssign(self): typ = parse_type( self.stmt.annotation, sigs=self.context.sigs, custom_structs=self.context.structs, ) varname = self.stmt.target.id pos = self.context.new_variable(varname, typ) if self.stmt.value is None: return sub = Expr(self.stmt.value, self.context).ir_node is_literal_bytes32_assign = (isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32 and isinstance(typ, BaseType) and typ.typ == "bytes32" and sub.typ.is_literal) # If bytes[32] to bytes32 assignment rewrite sub as bytes32. if is_literal_bytes32_assign: sub = IRnode( util.bytes_to_int(self.stmt.value.s), typ=BaseType("bytes32"), ) variable_loc = IRnode.from_list(pos, typ=typ, location=MEMORY) ir_node = make_setter(variable_loc, sub) return ir_node
def ann_assign(self): self.context.set_in_assignment(True) typ = parse_type(self.stmt.annotation, location='memory', custom_units=self.context.custom_units) if isinstance(self.stmt.target, ast.Attribute) and self.stmt.target.value.id == 'self': raise TypeMismatchException('May not redefine storage variables.', self.stmt) varname = self.stmt.target.id pos = self.context.new_variable(varname, typ) o = LLLnode.from_list('pass', typ=None, pos=pos) if self.stmt.value is not None: sub = Expr(self.stmt.value, self.context).lll_node # If bytes[32] to bytes32 assignment rewrite sub as bytes32. if isinstance( sub.typ, ByteArrayType) and sub.typ.maxlen == 32 and isinstance( typ, BaseType) and typ.typ == 'bytes32': bytez, bytez_length = string_to_bytes(self.stmt.value.s) sub = LLLnode(bytes_to_int(bytez), typ=BaseType('bytes32'), pos=getpos(self.stmt)) self._check_valid_assign(sub) self._check_same_variable_assign(sub) variable_loc = LLLnode.from_list(pos, typ=typ, location='memory', pos=getpos(self.stmt)) o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt)) self.context.set_in_assignment(False) return o
def pack_logging_topics(event_id, args, expected_topics, context, pos): topics = [event_id] for pos, expected_topic in enumerate(expected_topics): expected_type = expected_topic.typ arg = args[pos] value = parse_expr(arg, context) arg_type = value.typ if isinstance(arg_type, ByteArrayType) and isinstance(expected_type, ByteArrayType): if arg_type.maxlen > expected_type.maxlen: raise TypeMismatchException("Topic input bytes are too big: %r %r" % (arg_type, expected_type), pos) if isinstance(arg, ast.Str): bytez, bytez_length = string_to_bytes(arg.s) if len(bytez) > 32: raise InvalidLiteralException("Can only log a maximum of 32 bytes at a time.", pos) topics.append(bytes_to_int(bytez + b'\x00' * (32 - bytez_length))) else: if value.location == "memory": size = ['mload', value] elif value.location == "storage": size = ['sload', ['sha3_32', value]] topics.append(byte_array_to_num(value, arg, 'uint256', size)) else: value = unwrap_location(value) value = base_type_conversion(value, arg_type, expected_type, pos=pos) topics.append(value) return topics
def string(self): bytez, bytez_length = string_to_bytes(self.expr.s) placeholder = self.context.new_placeholder(ByteArrayType(bytez_length)) seq = [] seq.append(['mstore', placeholder, bytez_length]) for i in range(0, len(bytez), 32): seq.append(['mstore', ['add', placeholder, i + 32], bytes_to_int((bytez + b'\x00' * 31)[i: i + 32])]) return LLLnode.from_list(['seq'] + seq + [placeholder], typ=ByteArrayType(bytez_length), location='memory', pos=getpos(self.expr))
def create_with_code_of(expr, args, kwargs, context): value = kwargs['value'] if value != zero_value: enforce_units(value.typ, get_keyword(expr, 'value'), BaseType('int128', {'wei': 1})) if context.is_constant: raise ConstancyViolationException("Cannot make calls from a constant function", expr) placeholder = context.new_placeholder(ByteArrayType(96)) kode = b'`.`\x0c`\x009`.`\x00\xf36`\x00`\x007a\x10\x00`\x006`\x00s\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\xf4\x15XWa\x10\x00`\x00\xf3' assert len(kode) <= 64 high = bytes_to_int(kode[:32]) low = bytes_to_int((kode + b'\x00' * 32)[47:79]) return LLLnode.from_list(['seq', ['mstore', placeholder, high], ['mstore', ['add', placeholder, 27], ['mul', args[0], 2**96]], ['mstore', ['add', placeholder, 47], low], ['clamp_nonzero', ['create', value, placeholder, 64]]], typ=BaseType('address'), pos=getpos(expr), add_gas_estimate=10000)
def _make_bytelike(self, btype, bytez, bytez_length): placeholder = self.context.new_placeholder(btype) seq = [] seq.append(['mstore', placeholder, bytez_length]) for i in range(0, len(bytez), 32): seq.append(['mstore', ['add', placeholder, i + 32], bytes_to_int((bytez + b'\x00' * 31)[i: i + 32])]) return LLLnode.from_list(['seq'] + seq + [placeholder], typ=btype, location='memory', pos=getpos(self.expr), annotation='Create %r: %s' % (btype, bytez))
def ann_assign(self): with self.context.assignment_scope(): typ = parse_type( self.stmt.annotation, location='memory', custom_units=self.context.custom_units, custom_structs=self.context.structs, constants=self.context.constants, ) if isinstance(self.stmt.target, ast.Attribute): raise TypeMismatchException( f'May not set type for field {self.stmt.target.attr}', self.stmt, ) varname = self.stmt.target.id pos = self.context.new_variable(varname, typ) o = LLLnode.from_list('pass', typ=None, pos=pos) if self.stmt.value is None: raise StructureException( 'New variables must be initialized explicitly', self.stmt) sub = Expr(self.stmt.value, self.context).lll_node # Disallow assignment to None if isinstance(sub.typ, NullType): raise InvalidLiteralException( ( 'Assignment to None is not allowed, use a default ' 'value or built-in `clear()`.' ), self.stmt ) is_valid_bytes32_assign = ( isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32 ) and isinstance(typ, BaseType) and typ.typ == 'bytes32' # If bytes[32] to bytes32 assignment rewrite sub as bytes32. if is_valid_bytes32_assign: sub = LLLnode( bytes_to_int(self.stmt.value.s), typ=BaseType('bytes32'), pos=getpos(self.stmt), ) self._check_valid_assign(sub) self._check_same_variable_assign(sub) variable_loc = LLLnode.from_list( pos, typ=typ, location='memory', pos=getpos(self.stmt), ) o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt)) # o.pos = getpos(self.stmt) # TODO: Should this be here like in assign()? return o
def from_declaration(cls, code, custom_units=None): name = code.target.id pos = 0 if not is_varname_valid(name, custom_units=custom_units): raise EventDeclarationException("Event name invalid: " + name) # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ... args = [] indexed_list = [] topics_count = 1 if code.annotation.args: keys = code.annotation.args[0].keys values = code.annotation.args[0].values for i in range(len(keys)): typ = values[i] arg = keys[i].id is_indexed = False # Check to see if argument is a topic if isinstance(typ, ast.Call) and typ.func.id == 'indexed': typ = values[i].args[0] indexed_list.append(True) topics_count += 1 is_indexed = True else: indexed_list.append(False) if isinstance(typ, ast.Subscript) and getattr( typ.value, 'id', None ) == 'bytes' and typ.slice.value.n > 32 and is_indexed: raise EventDeclarationException( "Indexed arguments are limited to 32 bytes") if topics_count > 4: raise EventDeclarationException( "Maximum of 3 topics {} given".format(topics_count - 1), arg) if not isinstance(arg, str): raise VariableDeclarationException("Argument name invalid", arg) if not typ: raise InvalidTypeException("Argument must have type", arg) if not is_varname_valid(arg, custom_units): raise VariableDeclarationException( "Argument name invalid or reserved: " + arg, arg) if arg in (x.name for x in args): raise VariableDeclarationException( "Duplicate function argument name: " + arg, arg) parsed_type = parse_type(typ, None, custom_units=custom_units) args.append(VariableRecord(arg, pos, parsed_type, False)) if isinstance(parsed_type, ByteArrayType): pos += ceil32(typ.slice.value.n) else: pos += get_size_of_type(parsed_type) * 32 sig = name + '(' + ','.join([ canonicalize_type(arg.typ, indexed_list[pos]) for pos, arg in enumerate(args) ]) + ')' # noqa F812 event_id = bytes_to_int(sha3(bytes(sig, 'utf-8'))) return cls(name, args, indexed_list, event_id, sig)
def keccak256_helper(expr, args, kwargs, context): sub = args[0] # Can hash literals if isinstance(sub, bytes): return LLLnode.from_list(bytes_to_int(keccak256(sub)), typ=BaseType("bytes32"), pos=getpos(expr)) # Can hash bytes32 objects if is_base_type(sub.typ, "bytes32"): return LLLnode.from_list( [ "seq", ["mstore", MemoryPositions.FREE_VAR_SPACE, sub], ["sha3", MemoryPositions.FREE_VAR_SPACE, 32], ], typ=BaseType("bytes32"), pos=getpos(expr), ) # Copy the data to an in-memory array if sub.location == "memory": # If we are hashing a value in memory, no need to copy it, just hash in-place return LLLnode.from_list( [ "with", "_sub", sub, ["sha3", ["add", "_sub", 32], ["mload", "_sub"]] ], typ=BaseType("bytes32"), pos=getpos(expr), ) elif sub.location == "storage": lengetter = LLLnode.from_list(["sload", ["sha3_32", "_sub"]], typ=BaseType("int128")) else: # This should never happen, but just left here for future compiler-writers. raise Exception( f"Unsupported location: {sub.location}") # pragma: no test placeholder = context.new_internal_variable(sub.typ) placeholder_node = LLLnode.from_list(placeholder, typ=sub.typ, location="memory") copier = make_byte_array_copier( placeholder_node, LLLnode.from_list("_sub", typ=sub.typ, location=sub.location), ) return LLLnode.from_list( [ "with", "_sub", sub, ["seq", copier, ["sha3", ["add", placeholder, 32], lengetter]] ], typ=BaseType("bytes32"), pos=getpos(expr), )
def from_declaration(cls, class_node, global_ctx): name = class_node.name pos = 0 check_valid_varname( name, global_ctx._structs, global_ctx._constants, pos=class_node, error_prefix="Event name invalid. ", exc=EventDeclarationException, ) args = [] indexed_list = [] if len(class_node.body) != 1 or not isinstance(class_node.body[0], vy_ast.Pass): for node in class_node.body: arg_item = node.target arg = node.target.id typ = node.annotation if isinstance(typ, vy_ast.Call) and typ.get("func.id") == "indexed": indexed_list.append(True) typ = typ.args[0] else: indexed_list.append(False) check_valid_varname( arg, global_ctx._structs, global_ctx._constants, pos=arg_item, error_prefix="Event argument name invalid or reserved.", ) if arg in (x.name for x in args): raise TypeCheckFailure( f"Duplicate function argument name: {arg}") # Can struct be logged? parsed_type = global_ctx.parse_type(typ, None) args.append(VariableRecord(arg, pos, parsed_type, False)) if isinstance(parsed_type, ByteArrayType): pos += ceil32(typ.slice.value.n) else: pos += get_size_of_type(parsed_type) * 32 sig = (name + "(" + ",".join([ canonicalize_type(arg.typ, indexed_list[pos]) for pos, arg in enumerate(args) ]) + ")") # noqa F812 event_id = bytes_to_int(keccak256(bytes(sig, "utf-8"))) return cls(name, args, indexed_list, event_id, sig)
def pack_logging_topics(event_id, arg_nodes, arg_types, context): topics = [event_id] for node, typ in zip(arg_nodes, arg_types): value = Expr(node, context).lll_node if isinstance(typ, ArrayValueAbstractType): if isinstance(node, (vy_ast.Str, vy_ast.Bytes)): # for literals, generate the topic at compile time value = node.value if isinstance(value, str): value = value.encode() topics.append(bytes_to_int(keccak256(value))) elif value.location == "memory": topics.append(["sha3", ["add", value, 32], ["mload", value]]) else: # storage or calldata placeholder = context.new_internal_variable(value.typ) placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory") copier = make_byte_array_copier( placeholder_node, LLLnode.from_list("_sub", typ=value.typ, location=value.location), ) lll_node = [ "with", "_sub", value, ["seq", copier, ["sha3", ["add", placeholder, 32], ["mload", placeholder]]], ] topics.append(lll_node) elif isinstance(typ, ArrayDefinition): size = typ.size_in_bytes if value.location == "memory": topics.append(["sha3", value, size]) else: # storage or calldata placeholder = context.new_internal_variable(value.typ) placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory") setter = make_setter(placeholder_node, value, "memory", value.pos) lll_node = ["seq", setter, ["sha3", placeholder, size]] topics.append(lll_node) else: value = unwrap_location(value) topics.append(value) return topics
def ann_assign(self): with self.context.assignment_scope(): typ = parse_type( self.stmt.annotation, location='memory', custom_structs=self.context.structs, constants=self.context.constants, ) if isinstance(self.stmt.target, vy_ast.Attribute): raise TypeMismatch( f'May not set type for field {self.stmt.target.attr}', self.stmt, ) varname = self.stmt.target.id pos = self.context.new_variable(varname, typ) if self.stmt.value is None: raise StructureException( 'New variables must be initialized explicitly', self.stmt) sub = Expr(self.stmt.value, self.context).lll_node is_literal_bytes32_assign = ( isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32 and isinstance(typ, BaseType) and typ.typ == 'bytes32' and sub.typ.is_literal ) # If bytes[32] to bytes32 assignment rewrite sub as bytes32. if is_literal_bytes32_assign: sub = LLLnode( bytes_to_int(self.stmt.value.s), typ=BaseType('bytes32'), pos=getpos(self.stmt), ) self._check_valid_assign(sub) self._check_same_variable_assign(sub) variable_loc = LLLnode.from_list( pos, typ=typ, location='memory', pos=getpos(self.stmt), ) o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt)) return o
def _make_bytelike(self, btype, bytez, bytez_length): placeholder = self.context.new_internal_variable(btype) seq = [] seq.append(["mstore", placeholder, bytez_length]) for i in range(0, len(bytez), 32): seq.append([ "mstore", ["add", placeholder, i + 32], bytes_to_int((bytez + b"\x00" * 31)[i:i + 32]), ]) return IRnode.from_list( ["seq"] + seq + [placeholder], typ=btype, location=MEMORY, annotation=f"Create {btype}: {bytez}", )
def _make_bytelike(self, btype, bytez, bytez_length): placeholder = self.context.new_placeholder(btype) seq = [] seq.append(["mstore", placeholder, bytez_length]) for i in range(0, len(bytez), 32): seq.append([ "mstore", ["add", placeholder, i + 32], bytes_to_int((bytez + b"\x00" * 31)[i:i + 32]), # noqa: E203 ]) return LLLnode.from_list( ["seq"] + seq + [placeholder], typ=btype, location="memory", pos=getpos(self.expr), annotation=f"Create {btype}: {bytez}", )
def pack_logging_topics(event_id, args, expected_topics, context, pos): topics = [event_id] code_pos = pos for pos, expected_topic in enumerate(expected_topics): expected_type = expected_topic.typ arg = args[pos] value = Expr(arg, context).lll_node arg_type = value.typ if isinstance(arg_type, ByteArrayLike) and isinstance( expected_type, ByteArrayLike): if arg_type.maxlen > expected_type.maxlen: raise TypeMismatch( f"Topic input bytes are too big: {arg_type} {expected_type}", code_pos) if isinstance(arg, vy_ast.Str): bytez, bytez_length = string_to_bytes(arg.s) if len(bytez) > 32: raise InvalidLiteral( "Can only log a maximum of 32 bytes at a time.", code_pos) topics.append( bytes_to_int(bytez + b'\x00' * (32 - bytez_length))) else: if value.location == "memory": size = ['mload', value] elif value.location == "storage": size = ['sload', ['sha3_32', value]] topics.append(byte_array_to_num(value, arg, 'uint256', size)) else: if arg_type != expected_type: raise TypeMismatch( f"Invalid type for logging topic, got {arg_type} expected {expected_type}", value.pos) value = unwrap_location(value) value = base_type_conversion(value, arg_type, expected_type, pos=code_pos) topics.append(value) return topics
def parse_AnnAssign(self): with self.context.assignment_scope(): typ = parse_type( self.stmt.annotation, location="memory", custom_structs=self.context.structs, constants=self.context.constants, ) varname = self.stmt.target.id pos = self.context.new_variable(varname, typ, pos=self.stmt) if self.stmt.value is None: return sub = Expr(self.stmt.value, self.context).lll_node is_literal_bytes32_assign = (isinstance(sub.typ, ByteArrayType) and sub.typ.maxlen == 32 and isinstance(typ, BaseType) and typ.typ == "bytes32" and sub.typ.is_literal) # If bytes[32] to bytes32 assignment rewrite sub as bytes32. if is_literal_bytes32_assign: sub = LLLnode( bytes_to_int(self.stmt.value.s), typ=BaseType("bytes32"), pos=getpos(self.stmt), ) variable_loc = LLLnode.from_list( pos, typ=typ, location="memory", pos=getpos(self.stmt), ) lll_node = make_setter(variable_loc, sub, "memory", pos=getpos(self.stmt)) return lll_node
def sha256(expr, args, kwargs, context): sub = args[0] # Literal input if isinstance(sub, bytes): return LLLnode.from_list( bytes_to_int(hashlib.sha256(sub).digest()), typ=BaseType('bytes32'), pos=getpos(expr) ) # bytes32 input elif is_base_type(sub.typ, 'bytes32'): return LLLnode.from_list( [ 'seq', ['mstore', MemoryPositions.FREE_VAR_SPACE, sub], _make_sha256_call( inp_start=MemoryPositions.FREE_VAR_SPACE, inp_len=32, out_start=MemoryPositions.FREE_VAR_SPACE, out_len=32 ), ['mload', MemoryPositions.FREE_VAR_SPACE] # push value onto stack ], typ=BaseType('bytes32'), pos=getpos(expr), add_gas_estimate=SHA256_BASE_GAS + 1 * SHA256_PER_WORD_GAS ) # bytearay-like input if sub.location == "storage": # Copy storage to memory placeholder = context.new_placeholder(sub.typ) placeholder_node = LLLnode.from_list(placeholder, typ=sub.typ, location='memory') copier = make_byte_array_copier( placeholder_node, LLLnode.from_list('_sub', typ=sub.typ, location=sub.location), ) return LLLnode.from_list( [ 'with', '_sub', sub, [ 'seq', copier, _make_sha256_call( inp_start=['add', placeholder, 32], inp_len=['mload', placeholder], out_start=MemoryPositions.FREE_VAR_SPACE, out_len=32 ), ['mload', MemoryPositions.FREE_VAR_SPACE] ], ], typ=BaseType('bytes32'), pos=getpos(expr), add_gas_estimate=SHA256_BASE_GAS + sub.typ.maxlen * SHA256_PER_WORD_GAS ) elif sub.location == "memory": return LLLnode.from_list( [ 'with', '_sub', sub, [ 'seq', _make_sha256_call( inp_start=['add', '_sub', 32], inp_len=['mload', '_sub'], out_start=MemoryPositions.FREE_VAR_SPACE, out_len=32 ), ['mload', MemoryPositions.FREE_VAR_SPACE] ] ], typ=BaseType('bytes32'), pos=getpos(expr), add_gas_estimate=SHA256_BASE_GAS + sub.typ.maxlen * SHA256_PER_WORD_GAS ) else: # This should never happen, but just left here for future compiler-writers. raise Exception("Unsupported location: %s" % sub.location) # pragma: no test
def pack_logging_topics(event_id, args, expected_topics, context, pos): topics = [event_id] code_pos = pos for pos, expected_topic in enumerate(expected_topics): expected_type = expected_topic.typ arg = args[pos] value = Expr(arg, context).lll_node arg_type = value.typ if isinstance(arg_type, ByteArrayLike) and isinstance(expected_type, ByteArrayLike): if arg_type.maxlen > expected_type.maxlen: raise TypeMismatch( f"Topic input bytes are too big: {arg_type} {expected_type}", code_pos ) if isinstance(arg, (vy_ast.Str, vy_ast.Bytes)): # for literals, generate the topic at compile time value = arg.value if isinstance(value, str): value = value.encode() topics.append(bytes_to_int(keccak256(value))) elif value.location == "memory": topics.append(["sha3", ["add", value, 32], ["mload", value]]) else: # storage or calldata placeholder = context.new_internal_variable(value.typ) placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory") copier = make_byte_array_copier( placeholder_node, LLLnode.from_list("_sub", typ=value.typ, location=value.location), ) lll_node = [ "with", "_sub", value, ["seq", copier, ["sha3", ["add", placeholder, 32], ["mload", placeholder]]], ] topics.append(lll_node) elif isinstance(arg_type, ListType) and isinstance(expected_type, ListType): size = get_size_of_type(value.typ) * 32 if value.location == "memory": topics.append(["sha3", value, size]) else: # storage or calldata placeholder = context.new_internal_variable(value.typ) placeholder_node = LLLnode.from_list(placeholder, typ=value.typ, location="memory") setter = make_setter(placeholder_node, value, "memory", value.pos) lll_node = ["seq", setter, ["sha3", placeholder, size]] topics.append(lll_node) else: if arg_type != expected_type: raise TypeMismatch( f"Invalid type for logging topic, got {arg_type} expected {expected_type}", value.pos, ) value = unwrap_location(value) value = base_type_conversion(value, arg_type, expected_type, pos=code_pos) topics.append(value) return topics
def from_declaration(cls, code, global_ctx): name = code.target.id pos = 0 check_valid_varname(name, global_ctx._custom_units, global_ctx._structs, global_ctx._constants, pos=code, error_prefix="Event name invalid. ", exc=EventDeclarationException) # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ... args = [] indexed_list = [] topics_count = 1 if code.annotation.args: keys = code.annotation.args[0].keys values = code.annotation.args[0].values for i in range(len(keys)): typ = values[i] if not isinstance(keys[i], ast.Name): raise EventDeclarationException( 'Invalid key type, expected a valid name.', keys[i], ) if not isinstance(typ, (ast.Name, ast.Call, ast.Subscript)): raise EventDeclarationException( 'Invalid event argument type.', typ) if isinstance(typ, ast.Call) and not isinstance(typ.func, ast.Name): raise EventDeclarationException( 'Invalid event argument type', typ) arg = keys[i].id arg_item = keys[i] is_indexed = False # Check to see if argument is a topic if isinstance(typ, ast.Call) and typ.func.id == 'indexed': typ = values[i].args[0] indexed_list.append(True) topics_count += 1 is_indexed = True else: indexed_list.append(False) if isinstance(typ, ast.Subscript) and getattr( typ.value, 'id', None ) == 'bytes' and typ.slice.value.n > 32 and is_indexed: # noqa: E501 raise EventDeclarationException( "Indexed arguments are limited to 32 bytes") if topics_count > 4: raise EventDeclarationException( f"Maximum of 3 topics {topics_count - 1} given", arg, ) if not isinstance(arg, str): raise VariableDeclarationException("Argument name invalid", arg) if not typ: raise InvalidTypeException("Argument must have type", arg) check_valid_varname( arg, global_ctx._custom_units, global_ctx._structs, global_ctx._constants, pos=arg_item, error_prefix="Event argument name invalid or reserved.", ) if arg in (x.name for x in args): raise VariableDeclarationException( "Duplicate function argument name: " + arg, arg_item, ) # Can struct be logged? parsed_type = global_ctx.parse_type(typ, None) args.append(VariableRecord(arg, pos, parsed_type, False)) if isinstance(parsed_type, ByteArrayType): pos += ceil32(typ.slice.value.n) else: pos += get_size_of_type(parsed_type) * 32 sig = name + '(' + ','.join([ canonicalize_type(arg.typ, indexed_list[pos]) for pos, arg in enumerate(args) ]) + ')' # noqa F812 event_id = bytes_to_int(keccak256(bytes(sig, 'utf-8'))) return cls(name, args, indexed_list, event_id, sig)