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('num')) else: raise Exception("Unsupported location: %s" % sub.location) 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 raw_call(expr, args, kwargs, context): to, data = args gas, value, outsize = kwargs['gas'], kwargs['value'], kwargs['outsize'] if context.is_constant: raise ConstancyViolationException( "Cannot make calls from a constant function", expr) if value != zero_value: enforce_units(value.typ, get_keyword(expr, 'value'), BaseType('num', {'wei': 1})) placeholder = context.new_placeholder(data.typ) placeholder_node = LLLnode.from_list(placeholder, typ=data.typ, location='memory') copier = make_byte_array_copier(placeholder_node, data) output_placeholder = context.new_placeholder(ByteArrayType(outsize)) output_node = LLLnode.from_list(output_placeholder, typ=ByteArrayType(outsize), location='memory') z = LLLnode.from_list([ 'seq', copier, [ 'assert', [ 'call', gas, to, value, ['add', placeholder_node, 32], ['mload', placeholder_node], ['add', output_node, 32], outsize ] ], ['mstore', output_node, outsize], output_node ], typ=ByteArrayType(outsize), location='memory', pos=getpos(expr)) return z
def raw_log(expr, args, kwargs, context): if not isinstance(args[0], ast.List) or len(args[0].elts) > 4: raise StructureException("Expecting a list of 0-4 topics as first argument", args[0]) topics = [] for elt in args[0].elts: arg = Expr.parse_value_expr(elt, context) if not is_base_type(arg.typ, 'bytes32'): raise TypeMismatchException("Expecting a bytes32 argument as topic", elt) topics.append(arg) if args[1].location == "memory": return LLLnode.from_list(["with", "_arr", args[1], ["log" + str(len(topics)), ["add", "_arr", 32], ["mload", "_arr"]] + topics], typ=None, pos=getpos(expr)) placeholder = context.new_placeholder(args[1].typ) placeholder_node = LLLnode.from_list(placeholder, typ=args[1].typ, location='memory') copier = make_byte_array_copier(placeholder_node, LLLnode.from_list('_sub', typ=args[1].typ, location=args[1].location)) return LLLnode.from_list( ["with", "_sub", args[1], ["seq", copier, ["log" + str(len(topics)), ["add", placeholder_node, 32], ["mload", placeholder_node]] + topics]], typ=None, pos=getpos(expr))
def _RLPlist(expr, args, kwargs, context): # Second argument must be a list of types if not isinstance(args[1], ast.List): raise TypeMismatchException("Expecting list of types for second argument", args[1]) if len(args[1].elts) == 0: raise TypeMismatchException("RLP list must have at least one item", expr) if len(args[1].elts) > 32: raise TypeMismatchException("RLP list must have at most 32 items", expr) # Get the output format _format = [] for arg in args[1].elts: if isinstance(arg, ast.Name) and arg.id == "bytes": subtyp = ByteArrayType(args[0].typ.maxlen) else: subtyp = parse_type(arg, 'memory') if not isinstance(subtyp, BaseType): raise TypeMismatchException("RLP lists only accept BaseTypes and byte arrays", arg) if not is_base_type(subtyp, ('num', 'num256', 'bytes32', 'address', 'bool')): raise TypeMismatchException("Unsupported base type: %s" % subtyp.typ, arg) _format.append(subtyp) output_type = TupleType(_format) output_placeholder_type = ByteArrayType((2 * len(_format) + 1 + get_size_of_type(output_type)) * 32) output_placeholder = context.new_placeholder(output_placeholder_type) output_node = LLLnode.from_list(output_placeholder, typ=output_placeholder_type, location='memory') # Create a decoder for each element in the tuple decoder = [] for i, typ in enumerate(_format): # Decoder for bytes32 if is_base_type(typ, 'bytes32'): decoder.append(LLLnode.from_list( ['seq', ['assert', ['eq', ['mload', ['add', output_node, ['mload', ['add', output_node, 32 * i]]]], 32]], ['mload', ['add', 32, ['add', output_node, ['mload', ['add', output_node, 32 * i]]]]]], typ, annotation='getting and checking bytes32 item')) # Decoder for address elif is_base_type(typ, 'address'): decoder.append(LLLnode.from_list( ['seq', ['assert', ['eq', ['mload', ['add', output_node, ['mload', ['add', output_node, 32 * i]]]], 20]], ['mod', ['mload', ['add', 20, ['add', output_node, ['mload', ['add', output_node, 32 * i]]]]], ['mload', MemoryPositions.ADDRSIZE]]], typ, annotation='getting and checking address item')) # Decoder for bytes elif isinstance(typ, ByteArrayType): decoder.append(LLLnode.from_list( ['add', output_node, ['mload', ['add', output_node, 32 * i]]], typ, location='memory', annotation='getting byte array')) # Decoder for num and num256 elif is_base_type(typ, ('num', 'num256')): bytez = LLLnode.from_list( ['add', output_node, ['mload', ['add', output_node, 32 * i]]], typ, location='memory', annotation='getting and checking %s' % typ.typ) decoder.append(byte_array_to_num(bytez, expr, typ.typ)) # Decoder for bools elif is_base_type(typ, ('bool')): # This is basically a really clever way to test for a length-prefixed one or zero. We take the 32 bytes # starting one byte *after* the start of the length declaration; this includes the last 31 bytes of the # length and the first byte of the value. 0 corresponds to length 0, first byte 0, and 257 corresponds # to length 1, first byte \x01 decoder.append(LLLnode.from_list( ['with', '_ans', ['mload', ['add', 1, ['add', output_node, ['mload', ['add', output_node, 32 * i]]]]], ['seq', ['assert', ['or', ['eq', '_ans', 0], ['eq', '_ans', 257]]], ['div', '_ans', 257]]], typ, annotation='getting and checking bool')) else: raise Exception("Type not yet supported") # Copy the input data to memory if args[0].location == "memory": variable_pointer = args[0] elif args[0].location == "storage": placeholder = context.new_placeholder(args[0].typ) placeholder_node = LLLnode.from_list(placeholder, typ=args[0].typ, location='memory') copier = make_byte_array_copier(placeholder_node, LLLnode.from_list('_ptr', typ=args[0].typ, location=args[0].location)) variable_pointer = ['with', '_ptr', args[0], ['seq', copier, placeholder_node]] else: raise Exception("Location not yet supported") # Decode the input data initial_setter = LLLnode.from_list( ['seq', ['with', '_sub', variable_pointer, ['pop', ['call', 1500 + 400 * len(_format) + 10 * len(args), LLLnode.from_list(RLP_DECODER_ADDRESS, annotation='RLP decoder'), 0, ['add', '_sub', 32], ['mload', '_sub'], output_node, 64 * len(_format) + 32 + 32 * get_size_of_type(output_type)]]], ['assert', ['eq', ['mload', output_node], 32 * len(_format) + 32]]], typ=None) # Shove the input data decoder in front of the first variable decoder decoder[0] = LLLnode.from_list(['seq', initial_setter, decoder[0]], typ=decoder[0].typ, location=decoder[0].location) return LLLnode.from_list(["multi"] + decoder, typ=output_type, location='memory', pos=getpos(expr))