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 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 variables(self): builtin_constants = { 'ZERO_ADDRESS': LLLnode.from_list([0], typ=BaseType('address', None, is_literal=True), pos=getpos(self.expr)), 'MAX_INT128': LLLnode.from_list(['mload', MemoryPositions.MAXNUM], typ=BaseType('int128', None, is_literal=True), pos=getpos(self.expr)), 'MIN_INT128': LLLnode.from_list(['mload', MemoryPositions.MINNUM], typ=BaseType('int128', None, is_literal=True), pos=getpos(self.expr)), 'MAX_DECIMAL': LLLnode.from_list(['mload', MemoryPositions.MAXDECIMAL], typ=BaseType('decimal', None, is_literal=True), pos=getpos(self.expr)), 'MIN_DECIMAL': LLLnode.from_list(['mload', MemoryPositions.MINDECIMAL], typ=BaseType('decimal', None, is_literal=True), pos=getpos(self.expr)), 'MAX_UINT256': LLLnode.from_list([2**256 - 1], typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr)), } if self.expr.id == 'self': return LLLnode.from_list(['address'], typ='address', pos=getpos(self.expr)) elif self.expr.id in self.context.vars: var = self.context.vars[self.expr.id] return LLLnode.from_list(var.pos, typ=var.typ, location='memory', pos=getpos(self.expr), annotation=self.expr.id, mutable=var.mutable) elif self.expr.id in builtin_constants: return builtin_constants[self.expr.id] elif self.expr.id in self.context.constants: # check if value is compatible with const = self.context.constants[self.expr.id] if isinstance(const, ast.AnnAssign): # Handle ByteArrays. expr = Expr(const.value, self.context).lll_node return expr # Other types are already unwrapped, no need return self.context.constants[self.expr.id] else: raise VariableDeclarationException("Undeclared variable: " + self.expr.id, self.expr)
def call_self_public(stmt_expr, context, sig): # self.* style call to a public function. method_name, expr_args, sig = call_lookup_specs(stmt_expr, context) add_gas = sig.gas # gas of call inargs, inargsize, _ = pack_arguments(sig, expr_args, context, pos=getpos(stmt_expr)) output_placeholder, returner, output_size = call_make_placeholder( stmt_expr, context, sig) assert_call = [ 'assert', [ 'call', ['gas'], ['address'], 0, inargs, inargsize, output_placeholder, output_size ] ] if output_size > 0: assert_call = ['seq', assert_call, returner] o = LLLnode.from_list(assert_call, typ=sig.output_type, location='memory', pos=getpos(stmt_expr), add_gas_estimate=add_gas, annotation='Internal Call: %s' % method_name) o.gas += sig.gas return o
def constants(self): if self.expr.value is True: return LLLnode.from_list(1, typ=BaseType('bool', is_literal=True), pos=getpos(self.expr)) elif self.expr.value is False: return LLLnode.from_list(0, typ=BaseType('bool', is_literal=True), pos=getpos(self.expr)) elif self.expr.value is None: return LLLnode.from_list(None, typ=NullType(), pos=getpos(self.expr)) else: raise Exception("Unknown name constant: %r" % self.expr.value.value)
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 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 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 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 tuple_literals(self): if not len(self.expr.elts): raise StructureException("Tuple must have elements", self.expr) o = [] for elt in self.expr.elts: o.append(Expr(elt, self.context).lll_node) return LLLnode.from_list(["multi"] + o, typ=TupleType(o), pos=getpos(self.expr))
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 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 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 build_in_comparator(self): from ophydia.parser.parser import make_setter left = Expr(self.expr.left, self.context).lll_node right = Expr(self.expr.comparators[0], self.context).lll_node if left.typ.typ != right.typ.subtype.typ: raise TypeMismatchException("%s cannot be in a list of %s" % (left.typ.typ, right.typ.subtype.typ)) result_placeholder = self.context.new_placeholder(BaseType('bool')) setter = [] # Load nth item from list in memory. if right.value == 'multi': # Copy literal to memory to be compared. tmp_list = LLLnode.from_list( obj=self.context.new_placeholder(ListType(right.typ.subtype, right.typ.count)), typ=ListType(right.typ.subtype, right.typ.count), location='memory' ) setter = make_setter(tmp_list, right, 'memory', pos=getpos(self.expr)) load_i_from_list = ['mload', ['add', tmp_list, ['mul', 32, ['mload', MemoryPositions.FREE_LOOP_INDEX]]]] elif right.location == "storage": load_i_from_list = ['sload', ['add', ['sha3_32', right], ['mload', MemoryPositions.FREE_LOOP_INDEX]]] else: load_i_from_list = ['mload', ['add', right, ['mul', 32, ['mload', MemoryPositions.FREE_LOOP_INDEX]]]] # Condition repeat loop has to break on. break_loop_condition = [ 'if', ['eq', unwrap_location(left), load_i_from_list], ['seq', ['mstore', '_result', 1], # store true. 'break'] ] # Repeat loop to loop-compare each item in the list. for_loop_sequence = [ ['mstore', result_placeholder, 0], ['with', '_result', result_placeholder, ['repeat', MemoryPositions.FREE_LOOP_INDEX, 0, right.typ.count, break_loop_condition]], ['mload', result_placeholder] ] # Save list to memory, so one can iterate over it, # used when literal was created with tmp_list. if setter: compare_sequence = ['seq', setter] + for_loop_sequence else: compare_sequence = ['seq'] + for_loop_sequence # Compare the result of the repeat loop to 1, to know if a match was found. o = LLLnode.from_list([ 'eq', 1, compare_sequence], typ='bool', annotation="in comporator" ) return o
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), annotation='Create ByteArray: %s' % bytez)
def parse_body(code, context): if not isinstance(code, list): return parse_stmt(code, context) o = [] for stmt in code: lll = parse_stmt(stmt, context) o.append(lll) return LLLnode.from_list(['seq'] + o, pos=getpos(code[0]) if code else None)
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 _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 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 unary_operations(self): operand = Expr.parse_value_expr(self.expr.operand, self.context) if isinstance(self.expr.op, ast.Not): if isinstance(operand.typ, BaseType) and operand.typ.typ == 'bool': return LLLnode.from_list(["iszero", operand], typ='bool', pos=getpos(self.expr)) else: raise TypeMismatchException("Only bool is supported for not operation, %r supplied." % operand.typ, self.expr) elif isinstance(self.expr.op, ast.USub): if not is_numeric_type(operand.typ): raise TypeMismatchException("Unsupported type for negation: %r" % operand.typ, operand) if operand.typ.is_literal and 'int' in operand.typ.typ: num = ast.Num(0 - operand.value) num.source_code = self.expr.source_code num.lineno = self.expr.lineno num.col_offset = self.expr.col_offset return Expr.parse_value_expr(num, self.context) return LLLnode.from_list(["sub", 0, operand], typ=operand.typ, pos=getpos(self.expr)) else: raise StructureException("Only the 'not' unary operator is supported")
def make_call(stmt_expr, context): method_name, _, sig = call_lookup_specs(stmt_expr, context) if context.is_constant and not sig.const: raise ConstancyViolationException( "May not call non-constant function '%s' within a constant function." % (method_name), getpos(stmt_expr)) if sig.private: return call_self_private(stmt_expr, context, sig) else: return call_self_public(stmt_expr, context, sig)
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 external_contract_call(node, context, contract_name, contract_address, pos, value=None, gas=None): if value is None: value = 0 if gas is None: gas = 'gas' if contract_name not in context.sigs: raise VariableDeclarationException("Contract not declared yet: %s" % contract_name) method_name = node.func.attr if method_name not in context.sigs[contract_name]: raise FunctionDeclarationException( "Function not declared yet: %s (reminder: " "function must be declared in the correct contract)" % method_name, pos) sig = context.sigs[contract_name][method_name] inargs, inargsize, _ = pack_arguments( sig, [parse_expr(arg, context) for arg in node.args], context, pos=pos) output_placeholder, output_size, returner = get_external_contract_call_output( sig, context) sub = [ 'seq', ['assert', ['extcodesize', contract_address]], ['assert', ['ne', 'address', contract_address]] ] if context.is_constant or sig.const: sub.append([ 'assert', [ 'staticcall', gas, contract_address, inargs, inargsize, output_placeholder, output_size ] ]) else: sub.append([ 'assert', [ 'call', gas, contract_address, value, inargs, inargsize, output_placeholder, output_size ] ]) sub.extend(returner) o = LLLnode.from_list(sub, typ=sig.output_type, location='memory', pos=getpos(node)) return o
def list_literals(self): if not len(self.expr.elts): raise StructureException("List must have elements", self.expr) o = [] out_type = None for elt in self.expr.elts: o.append(Expr(elt, self.context).lll_node) if not out_type: out_type = o[-1].typ previous_type = o[-1].typ.subtype.typ if hasattr(o[-1].typ, 'subtype') else o[-1].typ current_type = out_type.subtype.typ if hasattr(out_type, 'subtype') else out_type if len(o) > 1 and previous_type != current_type: raise TypeMismatchException("Lists may only contain one type", self.expr) return LLLnode.from_list(["multi"] + o, typ=ListType(out_type, len(o)), pos=getpos(self.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
def number(self): orignum = get_original_if_0_prefixed(self.expr, self.context) if orignum is None and isinstance(self.expr.n, int): # Literal (mostly likely) becomes int128 if SizeLimits.in_bounds('int128', self.expr.n) or self.expr.n < 0: return LLLnode.from_list(self.expr.n, typ=BaseType('int128', unit=None, is_literal=True), pos=getpos(self.expr)) # Literal is large enough (mostly likely) becomes uint256. else: return LLLnode.from_list(self.expr.n, typ=BaseType('uint256', unit=None, is_literal=True), pos=getpos(self.expr)) elif isinstance(self.expr.n, float): numstring, num, den = get_number_as_fraction(self.expr, self.context) # if not SizeLimits.in_bounds('decimal', num // den): # if not SizeLimits.MINDECIMAL * den <= num <= SizeLimits.MAXDECIMAL * den: if not (SizeLimits.MINNUM * den < num < SizeLimits.MAXNUM * den): raise InvalidLiteralException("Number out of range: " + numstring, self.expr) if DECIMAL_DIVISOR % den: raise InvalidLiteralException("Too many decimal places: " + numstring, self.expr) return LLLnode.from_list(num * DECIMAL_DIVISOR // den, typ=BaseType('decimal', unit=None), pos=getpos(self.expr)) # Binary literal. elif orignum[:2] == '0b': str_val = orignum[2:] total_bits = len(orignum[2:]) total_bits = total_bits if total_bits % 8 == 0 else total_bits + 8 - (total_bits % 8) # ceil8 to get byte length. if len(orignum[2:]) != total_bits: # Support only full formed bit definitions. raise InvalidLiteralException("Bit notation requires a multiple of 8 bits / 1 byte. {} bit(s) are missing.".format(total_bits - len(orignum[2:])), self.expr) byte_len = int(total_bits / 8) placeholder = self.context.new_placeholder(ByteArrayType(byte_len)) seq = [] seq.append(['mstore', placeholder, byte_len]) for i in range(0, total_bits, 256): section = str_val[i:i + 256] int_val = int(section, 2) << (256 - len(section)) # bytes are right padded. seq.append( ['mstore', ['add', placeholder, i + 32], int_val]) return LLLnode.from_list(['seq'] + seq + [placeholder], typ=ByteArrayType(byte_len), location='memory', pos=getpos(self.expr), annotation='Create ByteArray (Binary literal): %s' % str_val) elif len(orignum) == 42: if checksum_encode(orignum) != orignum: raise InvalidLiteralException("Address checksum mismatch. If you are sure this is the " "right address, the correct checksummed form is: " + checksum_encode(orignum), self.expr) return LLLnode.from_list(self.expr.n, typ=BaseType('address', is_literal=True), pos=getpos(self.expr)) elif len(orignum) == 66: return LLLnode.from_list(self.expr.n, typ=BaseType('bytes32', is_literal=True), pos=getpos(self.expr)) else: raise InvalidLiteralException("Cannot read 0x value with length %d. Expecting 42 (address incl 0x) or 66 (bytes32 incl 0x)" % len(orignum), self.expr)