def parse_name(self): if self.stmt.id == "vdb": return LLLnode('debugger', typ=None, pos=getpos(self.stmt)) elif self.stmt.id == "throw": return LLLnode.from_list(['assert', 0], typ=None, pos=getpos(self.stmt)) else: raise StructureException("Unsupported statement type: %s" % type(self.stmt), self.stmt)
def to_uint256(expr, args, kwargs, context): in_node = args[0] input_type, len = get_type(in_node) if isinstance(in_node, int): if not SizeLimits.in_bounds('uint256', in_node): raise InvalidLiteralException( "Number out of range: {}".format(in_node)) _unit = in_node.typ.unit if input_type == 'int128' else None return LLLnode.from_list(in_node, typ=BaseType('uint256', _unit), pos=getpos(expr)) elif isinstance(in_node, LLLnode) and input_type in ('int128', 'num_literal'): _unit = in_node.typ.unit if input_type == 'int128' else None return LLLnode.from_list(['clampge', in_node, 0], typ=BaseType('uint256', _unit), pos=getpos(expr)) elif isinstance(in_node, LLLnode) and input_type in ('bytes32', 'address'): return LLLnode(value=in_node.value, args=in_node.args, typ=BaseType('uint256'), pos=getpos(expr)) else: raise InvalidLiteralException( "Invalid input for uint256: %r" % in_node, expr)
def call(self): from .parser import ( pack_logging_data, pack_logging_topics, external_contract_call, ) if isinstance(self.stmt.func, ast.Name): if self.stmt.func.id in stmt_dispatch_table: return stmt_dispatch_table[self.stmt.func.id](self.stmt, self.context) elif self.stmt.func.id in dispatch_table: raise StructureException("Function {} can not be called without being used.".format(self.stmt.func.id), self.stmt) else: raise StructureException("Unknown function: '{}'.".format(self.stmt.func.id), self.stmt) elif isinstance(self.stmt.func, ast.Attribute) and isinstance(self.stmt.func.value, ast.Name) and self.stmt.func.value.id == "self": return self_call.make_call(self.stmt, self.context) elif isinstance(self.stmt.func, ast.Attribute) and isinstance(self.stmt.func.value, ast.Call): contract_name = self.stmt.func.value.func.id contract_address = Expr.parse_value_expr(self.stmt.func.value.args[0], self.context) return external_contract_call(self.stmt, self.context, contract_name, contract_address, pos=getpos(self.stmt)) elif isinstance(self.stmt.func.value, ast.Attribute) and self.stmt.func.value.attr in self.context.sigs: contract_name = self.stmt.func.value.attr var = self.context.globals[self.stmt.func.value.attr] contract_address = unwrap_location(LLLnode.from_list(var.pos, typ=var.typ, location='storage', pos=getpos(self.stmt), annotation='self.' + self.stmt.func.value.attr)) return external_contract_call(self.stmt, self.context, contract_name, contract_address, pos=getpos(self.stmt)) elif isinstance(self.stmt.func.value, ast.Attribute) and self.stmt.func.value.attr in self.context.globals: contract_name = self.context.globals[self.stmt.func.value.attr].typ.unit var = self.context.globals[self.stmt.func.value.attr] contract_address = unwrap_location(LLLnode.from_list(var.pos, typ=var.typ, location='storage', pos=getpos(self.stmt), annotation='self.' + self.stmt.func.value.attr)) return external_contract_call(self.stmt, self.context, contract_name, contract_address, pos=getpos(self.stmt)) elif isinstance(self.stmt.func, ast.Attribute) and self.stmt.func.value.id == 'log': if self.stmt.func.attr not in self.context.sigs['self']: raise EventDeclarationException("Event not declared yet: %s" % self.stmt.func.attr) event = self.context.sigs['self'][self.stmt.func.attr] if len(event.indexed_list) != len(self.stmt.args): raise EventDeclarationException("%s received %s arguments but expected %s" % (event.name, len(self.stmt.args), len(event.indexed_list))) expected_topics, topics = [], [] expected_data, data = [], [] for pos, is_indexed in enumerate(event.indexed_list): if is_indexed: expected_topics.append(event.args[pos]) topics.append(self.stmt.args[pos]) else: expected_data.append(event.args[pos]) data.append(self.stmt.args[pos]) topics = pack_logging_topics(event.event_id, topics, expected_topics, self.context, pos=getpos(self.stmt)) inargs, inargsize, inargsize_node, inarg_start = pack_logging_data(expected_data, data, self.context, pos=getpos(self.stmt)) if inargsize_node is None: sz = inargsize else: sz = ['mload', inargsize_node] return LLLnode.from_list(['seq', inargs, LLLnode.from_list(["log" + str(len(topics)), inarg_start, sz] + topics, add_gas_estimate=inargsize * 10)], typ=None, pos=getpos(self.stmt)) else: raise StructureException("Unsupported operator: %r" % ast.dump(self.stmt), self.stmt)
def raw_call(expr, args, kwargs, context): to, data = args gas, value, outsize, delegate_call = kwargs['gas'], kwargs[ 'value'], kwargs['outsize'], kwargs['delegate_call'] if delegate_call.typ.is_literal is False: raise TypeMismatchException( 'The delegate_call parameter has to be a static/literal boolean value.' ) 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('uint256', {'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, pos=getpos(expr)) output_placeholder = context.new_placeholder(ByteArrayType(outsize)) output_node = LLLnode.from_list(output_placeholder, typ=ByteArrayType(outsize), location='memory') if delegate_call.value == 1: z = LLLnode.from_list([ 'seq', copier, [ 'assert', [ 'delegatecall', gas, to, ['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)) else: 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 _slice(expr, args, kwargs, context): sub, start, length = args[0], kwargs['start'], kwargs['len'] if not are_units_compatible(start.typ, BaseType('int128')): raise TypeMismatchException( "Type for slice start index must be a unitless number") # Expression representing the length of the slice if not are_units_compatible(length.typ, BaseType('int128')): raise TypeMismatchException( "Type for slice length must be a unitless number") # Node representing the position of the output in memory np = context.new_placeholder(ByteArrayType(maxlen=sub.typ.maxlen + 32)) placeholder_node = LLLnode.from_list(np, typ=sub.typ, location='memory') placeholder_plus_32_node = LLLnode.from_list(np + 32, typ=sub.typ, location='memory') # Copies over bytearray data if sub.location == 'storage': adj_sub = LLLnode.from_list( ['add', ['sha3_32', sub], ['add', ['div', '_start', 32], 1]], typ=sub.typ, location=sub.location) else: adj_sub = LLLnode.from_list([ 'add', sub, ['add', ['sub', '_start', ['mod', '_start', 32]], 32] ], typ=sub.typ, location=sub.location) copier = make_byte_slice_copier(placeholder_plus_32_node, adj_sub, ['add', '_length', 32], sub.typ.maxlen, pos=getpos(expr)) # New maximum length in the type of the result newmaxlen = length.value if not len(length.args) else sub.typ.maxlen maxlen = ['mload', Expr(sub, context=context).lll_node] # Retrieve length of the bytes. out = [ 'with', '_start', start, [ 'with', '_length', length, [ 'with', '_opos', ['add', placeholder_node, ['mod', '_start', 32]], [ 'seq', ['assert', ['le', ['add', '_start', '_length'], maxlen]], copier, ['mstore', '_opos', '_length'], '_opos' ] ] ] ] return LLLnode.from_list(out, typ=ByteArrayType(newmaxlen), location='memory', pos=getpos(expr))
def zero_pad(bytez_placeholder, maxlen): zero_padder = LLLnode.from_list(['pass']) if maxlen > 0: zero_pad_i = self.context.new_placeholder(BaseType('uint256')) # Iterator used to zero pad memory. zero_padder = LLLnode.from_list( ['repeat', zero_pad_i, ['mload', bytez_placeholder], maxlen, ['seq', ['if', ['gt', ['mload', zero_pad_i], maxlen], 'break'], # stay within allocated bounds ['mstore8', ['add', ['add', 32, bytez_placeholder], ['mload', zero_pad_i]], 0]]], annotation="Zero pad" ) return zero_padder
def replace_with_value(node, var, value): if node.value == "with" and node.args[0].value == var: return LLLnode(node.value, [ node.args[0], replace_with_value(node.args[1], var, value), node.args[2] ], node.typ, node.location, node.annotation) elif node.value == var: return LLLnode(value, [], node.typ, node.location, node.annotation) else: return LLLnode( node.value, [replace_with_value(arg, var, value) for arg in node.args], node.typ, node.location, node.annotation)
def to_decimal(expr, args, kwargs, context): input = args[0] if input.typ.typ == 'uint256': return LLLnode.from_list([ 'uclample', ['mul', input, DECIMAL_DIVISOR], ['mload', MemoryPositions.MAXDECIMAL] ], typ=BaseType('decimal', input.typ.unit, input.typ.positional), pos=getpos(expr)) else: return LLLnode.from_list(['mul', input, DECIMAL_DIVISOR], typ=BaseType('decimal', input.typ.unit, input.typ.positional), pos=getpos(expr))
def aug_assign(self): target = self.get_target(self.stmt.target) sub = Expr.parse_value_expr(self.stmt.value, self.context) if not isinstance(self.stmt.op, (ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod)): raise Exception("Unsupported operator for augassign") if not isinstance(target.typ, BaseType): raise TypeMismatchException("Can only use aug-assign operators with simple types!", self.stmt.target) if target.location == 'storage': o = Expr.parse_value_expr(ast.BinOp(left=LLLnode.from_list(['sload', '_stloc'], typ=target.typ, pos=target.pos), right=sub, op=self.stmt.op, lineno=self.stmt.lineno, col_offset=self.stmt.col_offset), self.context) return LLLnode.from_list(['with', '_stloc', target, ['sstore', '_stloc', base_type_conversion(o, o.typ, target.typ, pos=getpos(self.stmt))]], typ=None, pos=getpos(self.stmt)) elif target.location == 'memory': o = Expr.parse_value_expr(ast.BinOp(left=LLLnode.from_list(['mload', '_mloc'], typ=target.typ, pos=target.pos), right=sub, op=self.stmt.op, lineno=self.stmt.lineno, col_offset=self.stmt.col_offset), self.context) return LLLnode.from_list(['with', '_mloc', target, ['mstore', '_mloc', base_type_conversion(o, o.typ, target.typ, pos=getpos(self.stmt))]], typ=None, pos=getpos(self.stmt))
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 self._check_valid_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 minmax(expr, args, kwargs, context, is_min): def _can_compare_with_uint256(operand): if operand.typ.typ == 'uint256': return True elif operand.typ.typ == 'int128' and operand.typ.is_literal and SizeLimits.in_bounds( 'uint256', operand.value): return True return False left, right = args[0], args[1] if not are_units_compatible(left.typ, right.typ) and not are_units_compatible( right.typ, left.typ): raise TypeMismatchException("Units must be compatible", expr) if left.typ.typ == 'uint256': comparator = 'gt' if is_min else 'lt' else: comparator = 'sgt' if is_min else 'slt' if left.typ.typ == right.typ.typ: o = ['if', [comparator, '_l', '_r'], '_r', '_l'] otyp = left.typ otyp.is_literal = False elif _can_compare_with_uint256(left) and _can_compare_with_uint256(right): o = ['if', [comparator, '_l', '_r'], '_r', '_l'] if right.typ.typ == 'uint256': otyp = right.typ else: otyp = left.typ otyp.is_literal = False else: raise TypeMismatchException("Minmax types incompatible: %s %s" % (left.typ.typ, right.typ.typ)) return LLLnode.from_list(['with', '_l', left, ['with', '_r', right, o]], typ=otyp, pos=getpos(expr))
def selfdestruct(expr, args, kwargs, context): if context.is_constant: raise ConstancyViolationException( "Cannot %s inside a constant function!" % expr.func.id, expr.func) return LLLnode.from_list(['selfdestruct', args[0]], typ=None, pos=getpos(expr))
def blockhash(expr, args, kwargs, contact): return LLLnode.from_list([ 'blockhash', ['uclamplt', ['clampge', args[0], ['sub', ['number'], 256]], 'number'] ], typ=BaseType('bytes32'), pos=getpos(expr))
def parse_for(self): from .parser import ( parse_body, ) # Type 0 for, e.g. for i in list(): ... if self._is_list_iter(): return self.parse_for_list() if not isinstance(self.stmt.iter, ast.Call) or \ not isinstance(self.stmt.iter.func, ast.Name) or \ not isinstance(self.stmt.target, ast.Name) or \ self.stmt.iter.func.id != "range" or \ len(self.stmt.iter.args) not in (1, 2): raise StructureException("For statements must be of the form `for i in range(rounds): ..` or `for i in range(start, start + rounds): ..`", self.stmt.iter) # noqa block_scope_id = id(self.stmt.orelse) self.context.start_blockscope(block_scope_id) # Type 1 for, e.g. for i in range(10): ... if len(self.stmt.iter.args) == 1: if not isinstance(self.stmt.iter.args[0], ast.Num): raise StructureException("Range only accepts literal values", self.stmt.iter) start = LLLnode.from_list(0, typ='int128', pos=getpos(self.stmt)) rounds = self.stmt.iter.args[0].n elif isinstance(self.stmt.iter.args[0], ast.Num) and isinstance(self.stmt.iter.args[1], ast.Num): # Type 2 for, e.g. for i in range(100, 110): ... start = LLLnode.from_list(self.stmt.iter.args[0].n, typ='int128', pos=getpos(self.stmt)) rounds = LLLnode.from_list(self.stmt.iter.args[1].n - self.stmt.iter.args[0].n, typ='int128', pos=getpos(self.stmt)) else: # Type 3 for, e.g. for i in range(x, x + 10): ... if not isinstance(self.stmt.iter.args[1], ast.BinOp) or not isinstance(self.stmt.iter.args[1].op, ast.Add): raise StructureException("Two-arg for statements must be of the form `for i in range(start, start + rounds): ...`", self.stmt.iter.args[1]) if ast.dump(self.stmt.iter.args[0]) != ast.dump(self.stmt.iter.args[1].left): raise StructureException("Two-arg for statements of the form `for i in range(x, x + y): ...` must have x identical in both places: %r %r" % (ast.dump(self.stmt.iter.args[0]), ast.dump(self.stmt.iter.args[1].left)), self.stmt.iter) if not isinstance(self.stmt.iter.args[1].right, ast.Num): raise StructureException("Range only accepts literal values", self.stmt.iter.args[1]) start = Expr.parse_value_expr(self.stmt.iter.args[0], self.context) rounds = self.stmt.iter.args[1].right.n varname = self.stmt.target.id pos = self.context.new_variable(varname, BaseType('int128')) self.context.forvars[varname] = True o = LLLnode.from_list(['repeat', pos, start, rounds, parse_body(self.stmt.body, self.context)], typ=None, pos=getpos(self.stmt)) del self.context.vars[varname] del self.context.forvars[varname] self.context.end_blockscope(block_scope_id) return o
def ceil(expr, args, kwards, context): return LLLnode.from_list([ 'if', ['slt', args[0], 0], ['sdiv', args[0], DECIMAL_DIVISOR], ['sdiv', ['add', args[0], DECIMAL_DIVISOR - 1], DECIMAL_DIVISOR] ], typ=BaseType('int128', args[0].typ.unit, args[0].typ.positional), pos=getpos(expr))
def to_bytes32(expr, args, kwargs, context): input = args[0] typ, len = get_type(input) if typ == 'bytes': if len != 32: raise TypeMismatchException( "Unable to convert bytes[{}] to bytes32".format(len)) if input.location == "memory": return LLLnode.from_list(['mload', ['add', input, 32]], typ=BaseType('bytes32')) elif input.location == "storage": return LLLnode.from_list(['sload', ['add', ['sha3_32', input], 1]], typ=BaseType('bytes32')) else: return LLLnode(value=input.value, args=input.args, typ=BaseType('bytes32'), pos=getpos(expr))
def send(expr, args, kwargs, context): to, value = args if context.is_constant: raise ConstancyViolationException( "Cannot send ether inside a constant function!", expr) enforce_units(value.typ, expr.args[1], BaseType('uint256', {'wei': 1})) return LLLnode.from_list(['assert', ['call', 0, to, value, 0, 0, 0, 0]], typ=None, pos=getpos(expr))
def ecrecover(expr, args, kwargs, context): placeholder_node = LLLnode.from_list(context.new_placeholder( ByteArrayType(128)), typ=ByteArrayType(128), location='memory') return LLLnode.from_list([ 'seq', ['mstore', placeholder_node, args[0]], ['mstore', ['add', placeholder_node, 32], args[1]], ['mstore', ['add', placeholder_node, 64], args[2]], ['mstore', ['add', placeholder_node, 96], args[3]], [ 'pop', [ 'call', 3000, 1, 0, placeholder_node, 128, MemoryPositions.FREE_VAR_SPACE, 32 ] ], ['mload', MemoryPositions.FREE_VAR_SPACE] ], typ=BaseType('address'), pos=getpos(expr))
def method_id(expr, args, kwargs, context): if b' ' in args[0]: raise TypeMismatchException( 'Invalid function signature no spaces allowed.') method_id = fourbytes_to_int(sha3(args[0])[:4]) if args[1] == 'bytes32': return LLLnode(method_id, typ=BaseType('bytes32'), pos=getpos(expr)) elif args[1] == 'bytes[4]': placeholder = LLLnode.from_list( context.new_placeholder(ByteArrayType(4))) return LLLnode.from_list([ 'seq', ['mstore', ['add', placeholder, 4], method_id], ['mstore', placeholder, 4], placeholder ], typ=ByteArrayType(4), location='memory', pos=getpos(expr)) else: raise StructureException( 'Can only produce bytes32 or bytes[4] as outputs')
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), pos=getpos(expr)) 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 ecmul(expr, args, kwargs, context): placeholder_node = LLLnode.from_list(context.new_placeholder( ByteArrayType(128)), typ=ByteArrayType(128), location='memory') pos = getpos(expr) o = LLLnode.from_list([ 'seq', ['mstore', placeholder_node, avo(args[0], 0, pos)], ['mstore', ['add', placeholder_node, 32], avo(args[0], 1, pos)], ['mstore', ['add', placeholder_node, 64], args[1]], [ 'assert', ['call', 40000, 7, 0, placeholder_node, 96, placeholder_node, 64] ], placeholder_node ], typ=ListType(BaseType('uint256'), 2), pos=pos, location='memory') return o
def uint256_mulmod(expr, args, kwargs, context): return LLLnode.from_list([ 'seq', ['assert', args[2]], [ 'assert', [ 'or', ['iszero', args[0]], ['eq', ['div', ['mul', args[0], args[1]], args[0]], args[1]] ] ], ['mulmod', args[0], args[1], args[2]] ], typ=BaseType('uint256'), pos=getpos(expr))
def parse_assert(self): test_expr = Expr.parse_value_expr(self.stmt.test, self.context) if not self.is_bool_expr(test_expr): raise TypeMismatchException('Only boolean expressions allowed', self.stmt.test) if self.stmt.msg: if len(self.stmt.msg.s.strip()) == 0: raise StructureException('Empty reason string not allowed.', self.stmt) reason_str = self.stmt.msg.s.strip() sig_placeholder = self.context.new_placeholder(BaseType(32)) arg_placeholder = self.context.new_placeholder(BaseType(32)) reason_str_type = ByteArrayType(len(reason_str)) placeholder_bytes = Expr(self.stmt.msg, self.context).lll_node method_id = fourbytes_to_int(sha3(b"Error(string)")[:4]) assert_reason = \ ['seq', ['mstore', sig_placeholder, method_id], ['mstore', arg_placeholder, 32], placeholder_bytes, ['assert_reason', test_expr, int(sig_placeholder + 28), int(4 + 32 + get_size_of_type(reason_str_type) * 32)]] return LLLnode.from_list(assert_reason, typ=None, pos=getpos(self.stmt)) else: return LLLnode.from_list(['assert', test_expr], typ=None, pos=getpos(self.stmt))
def parse_delete(self): from .parser import ( make_setter, ) if len(self.stmt.targets) != 1: raise StructureException("Can delete one variable at a time", self.stmt) target = self.stmt.targets[0] target_lll = Expr(self.stmt.targets[0], self.context).lll_node if isinstance(target, ast.Subscript): if target_lll.location == "storage": return make_setter(target_lll, LLLnode.from_list(None, typ=NullType()), "storage", pos=getpos(self.stmt)) raise StructureException("Deleting type not supported.", self.stmt)
def to_int128(expr, args, kwargs, context): in_node = args[0] typ, len = get_type(in_node) if typ in ('uint256', 'bytes32'): if in_node.typ.is_literal and not SizeLimits.in_bounds( 'int128', in_node.value): raise InvalidLiteralException( "Number out of range: {}".format(in_node.value), expr) return LLLnode.from_list([ 'clamp', ['mload', MemoryPositions.MINNUM], in_node, ['mload', MemoryPositions.MAXNUM] ], typ=BaseType('int128', in_node.typ.unit), pos=getpos(expr)) else: return byte_array_to_num(in_node, expr, 'int128')
def as_wei_value(expr, args, kwargs, context): # Denominations names_denom = { (b"wei", ): 1, (b"femtoether", b"kwei", b"babbage"): 10**3, (b"picoether", b"mwei", b"lovelace"): 10**6, (b"nanoether", b"gwei", b"shannon"): 10**9, ( b"microether", b"szabo", ): 10**12, ( b"milliether", b"finney", ): 10**15, (b"ether", ): 10**18, (b"kether", b"grand"): 10**21, } for names, denom in names_denom.items(): if args[1] in names: denomination = denom break else: raise InvalidLiteralException("Invalid denomination: %s" % args[1], expr.args[1]) # Compute the amount of wei and return that value if isinstance(args[0], (int, float)): numstring, num, den = get_number_as_fraction(expr.args[0], context) if denomination % den: raise InvalidLiteralException( "Too many decimal places: %s" % numstring, expr.args[0]) sub = num * denomination // den elif args[0].typ.is_literal: if args[0].value <= 0: raise InvalidLiteralException("Negative wei value not allowed", expr) sub = ['mul', args[0].value, denomination] elif args[0].typ.typ == 'uint256': sub = ['mul', args[0], denomination] else: sub = ['div', ['mul', args[0], denomination], DECIMAL_DIVISOR] return LLLnode.from_list(sub, typ=BaseType('uint256', {'wei': 1}), location=None, pos=getpos(expr))
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 create_with_code_of(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( "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 shift(expr, args, kwargs, context): return LLLnode.from_list( [ 'with', '_v', args[0], [ 'with', '_s', args[1], # If second argument is positive, left-shift so multiply by a power of two # If it is negative, divide by a power of two # node that if the abs of the second argument >= 256, then in the EVM # 2**(second arg) = 0, and multiplying OR dividing by 0 gives 0 [ 'if', ['slt', '_s', 0], ['div', '_v', ['exp', 2, ['sub', 0, '_s']]], ['mul', '_v', ['exp', 2, '_s']] ] ] ], typ=BaseType('uint256'), pos=getpos(expr))
def assign(self): # Assignment (e.g. x[4] = y) if len(self.stmt.targets) != 1: raise StructureException("Assignment statement must have one target", self.stmt) self.context.set_in_assignment(True) sub = Expr(self.stmt.value, self.context).lll_node # Determine if it's an RLPList assignment. if isinstance(self.stmt.value, ast.Call) and getattr(self.stmt.value.func, 'id', '') is 'RLPList': pos = self.context.new_variable(self.stmt.targets[0].id, sub.typ) variable_loc = LLLnode.from_list(pos, typ=sub.typ, location='memory', pos=getpos(self.stmt), annotation=self.stmt.targets[0].id) o = make_setter(variable_loc, sub, 'memory', pos=getpos(self.stmt)) # All other assignments are forbidden. elif isinstance(self.stmt.targets[0], ast.Name) and self.stmt.targets[0].id not in self.context.vars: raise VariableDeclarationException("Variable type not defined", self.stmt) elif isinstance(self.stmt.targets[0], ast.Tuple) and isinstance(self.stmt.value, ast.Tuple): raise VariableDeclarationException("Tuple to tuple assignment not supported", self.stmt) else: # Checks to see if assignment is valid target = self.get_target(self.stmt.targets[0]) o = make_setter(target, sub, target.location, pos=getpos(self.stmt)) o.pos = getpos(self.stmt) self.context.set_in_assignment(False) return o