def num256_mod(expr, args, kwargs, context): return LLLnode.from_list(['mod', args[0], args[1]], typ=BaseType('num256'), pos=getpos(expr))
def as_num128(expr, args, kwargs, context): return LLLnode.from_list( ['clamp', ['mload', MemoryPositions.MINNUM], args[0], ['mload', MemoryPositions.MAXNUM]], typ=BaseType("num"), pos=getpos(expr) )
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.typ == 'num': sub = ['mul', args[0], denomination] else: sub = ['div', ['mul', args[0], denomination], DECIMAL_DIVISOR] return LLLnode.from_list(sub, typ=BaseType('num', {'wei': 1}), location=None, pos=getpos(expr)) zero_value = LLLnode.from_list(0, typ=BaseType('num', {'wei': 1})) @signature('address', 'bytes', outsize='num_literal', gas='num', value=Optional('num', zero_value)) 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'),
def avo(arg, ind): return unwrap_location( add_variable_offset(arg, LLLnode.from_list(ind, 'num')))
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))
def as_unitless_number(expr, args, kwargs, context): return LLLnode(value=args[0].value, args=args[0].args, typ=BaseType(args[0].typ.typ, {}), pos=getpos(expr))
def concat(expr, context): args = [Expr(arg, context).lll_node for arg in expr.args] if len(args) < 2: raise StructureException("Concat expects at least two arguments", expr) for expr_arg, arg in zip(expr.args, args): if not isinstance(arg.typ, ByteArrayType) and not is_base_type( arg.typ, 'bytes32') and not is_base_type(arg.typ, 'method_id'): raise TypeMismatchException( "Concat expects byte arrays or bytes32 objects", expr_arg) # Maximum length of the output total_maxlen = sum([ arg.typ.maxlen if isinstance(arg.typ, ByteArrayType) else 32 for arg in args ]) # Node representing the position of the output in memory placeholder = context.new_placeholder(ByteArrayType(total_maxlen)) # Object representing the output seq = [] # For each argument we are concatenating... for arg in args: # Start pasting into a position the starts at zero, and keeps # incrementing as we concatenate arguments placeholder_node = LLLnode.from_list(['add', placeholder, '_poz'], typ=ByteArrayType(total_maxlen), location='memory') placeholder_node_plus_32 = LLLnode.from_list( ['add', ['add', placeholder, '_poz'], 32], typ=ByteArrayType(total_maxlen), location='memory') if isinstance(arg.typ, ByteArrayType): # Ignore empty strings if arg.typ.maxlen == 0: continue # Get the length of the current argument if arg.location == "memory": length = LLLnode.from_list(['mload', '_arg'], typ=BaseType('num')) argstart = LLLnode.from_list(['add', '_arg', 32], typ=arg.typ, location=arg.location) elif arg.location == "storage": length = LLLnode.from_list(['sload', ['sha3_32', '_arg']], typ=BaseType('num')) argstart = LLLnode.from_list(['add', ['sha3_32', '_arg'], 1], typ=arg.typ, location=arg.location) # Make a copier to copy over data from that argyument seq.append([ 'with', '_arg', arg, [ 'seq', make_byte_slice_copier(placeholder_node_plus_32, argstart, length, arg.typ.maxlen), # Change the position to start at the correct # place to paste the next value ['set', '_poz', ['add', '_poz', length]] ] ]) elif isinstance(arg.typ, BaseType) and arg.typ.typ == "method_id": seq.append([ 'seq', ['mstore', ['add', placeholder_node, 32], arg.value * 2**224], ['set', '_poz', ['add', '_poz', 4]] ]) else: seq.append([ 'seq', [ 'mstore', ['add', placeholder_node, 32], unwrap_location(arg) ], ['set', '_poz', ['add', '_poz', 32]] ]) # The position, after all arguments are processing, equals the total # length. Paste this in to make the output a proper bytearray seq.append(['mstore', placeholder, '_poz']) # Memory location of the output seq.append(placeholder) return LLLnode.from_list(['with', '_poz', 0, ['seq'] + seq], typ=ByteArrayType(total_maxlen), location='memory', pos=getpos(expr))
def num256_mul(expr, args, kwargs, context): return LLLnode.from_list(['seq', # Checks that: a == 0 || a / b == b ['assert', ['or', ['iszero', args[0]], ['eq', ['div', ['mul', args[0], args[1]], args[0]], args[1]]]], ['mul', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
def num256_div(expr, args, kwargs, context): return LLLnode.from_list(['seq', # Checks that: b != 0 ['assert', args[1]], ['div', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
def num256_add(expr, args, kwargs, context): return LLLnode.from_list(['seq', # Checks that: a + b > a ['assert', ['or', ['iszero', args[1]], ['gt', ['add', args[0], args[1]], args[0]]]], ['add', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
def num256_sub(expr, args, kwargs, context): return LLLnode.from_list(['seq', # Checks that: a >= b ['assert', ['ge', args[0], args[1]]], ['sub', args[0], args[1]]], typ=BaseType('num256'), 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 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 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('num', {'wei': 1})) return LLLnode.from_list(['assert', ['call', 0, to, value, 0, 0, 0, 0]], typ=None, pos=getpos(expr))
def num256_le(expr, args, kwargs, context): return LLLnode.from_list(['le', args[0], args[1]], typ=BaseType('bool'), pos=getpos(expr))
def num256_exp(expr, args, kwargs, context): return LLLnode.from_list(['seq', ['assert', ['or', ['or', ['eq', args[1], 1], ['iszero', args[1]]], ['lt', args[0], ['exp', args[0], args[1]]]]], ['exp', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
def floor(expr, args, kwargs, context): return LLLnode.from_list(['sdiv', args[0], DECIMAL_DIVISOR], typ=BaseType('num', args[0].typ.unit, args[0].typ.positional), pos=getpos(expr))
def num256_mulmod(expr, args, kwargs, context): return LLLnode.from_list(['seq', ['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('num256'), pos=getpos(expr))
def as_bytes32(expr, args, kwargs, context): return LLLnode(value=args[0].value, args=args[0].args, typ=BaseType('bytes32'), pos=getpos(expr))
def lll_compiler(lll): lll = optimizer.optimize(LLLnode.from_list(lll)) byte_code = compile_lll.assembly_to_evm( compile_lll.compile_to_assembly(lll)) t.s.tx(to=b'', data=byte_code)
def method_id(expr, args, kwargs, context): method_id = fourbytes_to_int(sha3(args[0])[:4]) return LLLnode(method_id, typ=BaseType('method_id'), pos=getpos(expr))
def optimize(node): argz = [optimize(arg) for arg in node.args] if node.value in arith and int_at(argz, 0) and int_at(argz, 1): left, right = get_int_at(argz, 0), get_int_at(argz, 1) calcer, symb = arith[node.value] new_value = calcer(left, right) if argz[0].annotation and argz[1].annotation: annotation = argz[0].annotation + symb + argz[1].annotation elif argz[0].annotation or argz[1].annotation: annotation = (argz[0].annotation or str(left)) + symb + ( argz[1].annotation or str(right)) else: annotation = '' return LLLnode(new_value, [], node.typ, None, node.pos, annotation) elif node.value == "add" and int_at( argz, 0) and argz[1].value == "add" and int_at(argz[1].args, 0): calcer, symb = arith[node.value] if argz[0].annotation and argz[1].args[0].annotation: annotation = argz[0].annotation + symb + argz[1].args[0].annotation elif argz[0].annotation or argz[1].args[0].annotation: annotation = (argz[0].annotation or str(argz[0].value)) + symb + ( argz[1].args[0].annotation or str(argz[1].args[0].value)) else: annotation = '' return LLLnode("add", [ LLLnode(argz[0].value + argz[1].args[0].value, annotation=annotation), argz[1].args[1] ], node.typ, None, node.annotation) elif node.value == "add" and get_int_at(argz, 0) == 0: return LLLnode(argz[1].value, argz[1].args, node.typ, node.location, node.pos, argz[1].annotation) elif node.value == "add" and get_int_at(argz, 1) == 0: return LLLnode(argz[0].value, argz[0].args, node.typ, node.location, node.pos, argz[0].annotation) elif node.value == "clamp" and int_at(argz, 0) and int_at( argz, 1) and int_at(argz, 2): if get_int_at(argz, 0, True) > get_int_at(argz, 1, True): raise Exception("Clamp always fails") elif get_int_at(argz, 1, True) > get_int_at(argz, 2, True): raise Exception("Clamp always fails") else: return argz[1] elif node.value == "clamp" and int_at(argz, 0) and int_at(argz, 1): if get_int_at(argz, 0, True) > get_int_at(argz, 1, True): raise Exception("Clamp always fails") else: return LLLnode("clample", [argz[1], argz[2]], node.typ, node.location, node.pos, node.annotation) elif node.value == "clamp_nonzero" and int_at(argz, 0): if get_int_at(argz, 0) != 0: return LLLnode(argz[0].value, [], node.typ, node.location, node.pos, node.annotation) else: raise Exception("Clamp always fails") # Turns out this is actually not such a good optimization after all elif node.value == "with" and int_at( argz, 1) and not search_for_set(argz[2], argz[0].value) and False: o = replace_with_value(argz[2], argz[0].value, argz[1].value) return o elif node.value == "seq": o = [] for arg in argz: if arg.value == "seq": o.extend(arg.args) elif arg.value != "pass": o.append(arg) return LLLnode(node.value, o, node.typ, node.location, node.pos, node.annotation, add_gas_estimate=node.add_gas_estimate) elif hasattr(node, 'total_gas'): o = LLLnode(node.value, argz, node.typ, node.location, node.pos, node.annotation) o.total_gas = node.total_gas - node.gas + o.gas o.func_name = node.func_name return o else: return LLLnode(node.value, argz, node.typ, node.location, node.pos, node.annotation)
def extract32(expr, args, kwargs, context): sub, index = args ret_type = kwargs['type'] # Get length and specific element if sub.location == "memory": lengetter = LLLnode.from_list(['mload', '_sub'], typ=BaseType('num')) elementgetter = lambda index: LLLnode.from_list( ['mload', ['add', '_sub', ['add', 32, ['mul', 32, index]]]], typ=BaseType('num')) elif sub.location == "storage": lengetter = LLLnode.from_list(['sload', ['sha3_32', '_sub']], typ=BaseType('num')) elementgetter = lambda index: LLLnode.from_list( ['sload', ['add', ['sha3_32', '_sub'], ['add', 1, index]]], typ=BaseType('num')) # Special case: index known to be a multiple of 32 if isinstance(index.value, int) and not index.value % 32: o = LLLnode.from_list([ 'with', '_sub', sub, elementgetter( ['div', ['clamp', 0, index, ['sub', lengetter, 32]], 32]) ], typ=BaseType(ret_type), annotation='extracting 32 bytes') # General case else: o = LLLnode.from_list([ 'with', '_sub', sub, [ 'with', '_len', lengetter, [ 'with', '_index', ['clamp', 0, index, ['sub', '_len', 32]], [ 'with', '_mi32', ['mod', '_index', 32], [ 'with', '_di32', ['div', '_index', 32], [ 'if', '_mi32', [ 'add', [ 'mul', elementgetter('_di32'), ['exp', 256, '_mi32'] ], [ 'div', elementgetter(['add', '_di32', 1]), ['exp', 256, ['sub', 32, '_mi32']] ] ], elementgetter('_di32') ] ] ] ] ] ], typ=BaseType(ret_type), pos=getpos(expr), annotation='extracting 32 bytes') if ret_type == 'num128': return LLLnode.from_list([ 'clamp', ['mload', MemoryPositions.MINNUM], o, ['mload', MemoryPositions.MAXNUM] ], typ=BaseType("num"), pos=getpos(expr)) elif ret_type == 'address': return LLLnode.from_list( ['uclamplt', o, ['mload', MemoryPositions.ADDRSIZE]], typ=BaseType(ret_type), pos=getpos(expr)) else: return o
simple_factory_contract_bytecode, ) from tests.core.contract_fixtures.PAYGAS_contract import ( simple_forwarder_contract_lll_code, PAYGAS_contract_normal_lll_code, PAYGAS_contract_triggered_twice_lll_code, ) from tests.core.contract_fixtures.nonce_tracking_contract import ( nonce_tracking_lll_code, no_nonce_tracking_lll_code, ) DIR = os.path.dirname(__file__) simple_transfer_contract_bytecode = assembly_to_evm( compile_to_assembly(LLLnode.from_list(simple_transfer_contract_lll_code))) CREATE2_contract_bytecode = assembly_to_evm( compile_to_assembly(LLLnode.from_list(CREATE2_contract_lll_code))) CREATE2_json = { "simple_transfer_contract": { "bytecode": encode_hex(simple_transfer_contract_bytecode), "address": encode_hex( generate_CREATE2_contract_address( b'', simple_transfer_contract_bytecode)), }, "CREATE2_contract": { "bytecode":
def bitwise_or(expr, args, kwargs, context): return LLLnode.from_list(['or', args[0], args[1]], typ=BaseType('num256'), pos=getpos(expr))
rlp_decoder_lll = LLLnode.from_list([ 'seq', [ 'return', [0], [ 'lll', [ 'seq', ['mstore', position_index, 0], ['mstore', data_pos, 0], ['mstore', c, call_data_char(0)], ['mstore', i, 0], ['mstore', position_offset, 0], ['assert', ['ge', ['mload', c], 192]], # Must be a list [ 'if', ['lt', ['mload', c], 248], # if c < 248: [ 'seq', [ 'assert', ['eq', ['calldatasize'], sub(['mload', c], 191)] ], # assert ~calldatasize() == (c - 191) ['mstore', i, 1] # i = 1 ], [ 'seq', [ 'assert', [ 'eq', ['calldatasize'], add( sub(['mload', c], 246), call_data_bytes_as_int( 1, sub(['mload', c], 247))) ] ], # assert ~calldatasize() == (c - 246) + calldatabytes_as_int(1, c - 247) ['mstore', i, sub(['mload', c], 246)] # i = c - 246 ], ], # Main loop # Here, we simultaneously build up data in two places: # (i) starting from memory index 64, a list of 32-byte numbers # representing the start positions of each value # (ii) starting from memory index 1088, the values, in format # <length as 32 byte int> <value>, packed one after the other [ 'repeat', MemoryPositions.FREE_LOOP_INDEX, 1, 100, [ 'seq', ['if', ['ge', ['mload', i], 'calldatasize'], 'break'], ['mstore', c, call_data_char(['mload', i])], [ 'mstore', add(positions, ['mul', ['mload', position_index], 32]), ['mload', data_pos] ], [ 'mstore', position_index, add(['mload', position_index], 1) ], [ 'if', ['lt', ['mload', c], 128], [ 'seq', ['mstore', add(data, ['mload', data_pos]), 1], [ 'calldatacopy', add(data + 32, ['mload', data_pos]), ['mload', i], 1 ], ['mstore', i, add(['mload', i], 1)], [ 'mstore', data_pos, add(['mload', data_pos], 33) ] ], [ 'if', ['lt', ['mload', c], 184], [ 'seq', [ 'mstore', add(data, ['mload', data_pos]), sub(['mload', c], 128) ], [ 'calldatacopy', add(data + 32, ['mload', data_pos]), add(['mload', i], 1), sub(['mload', c], 128) ], [ 'if', ['eq', ['mload', c], 129], [ 'assert', [ 'ge', call_data_char( add(['mload', i], 1)), 128 ] ] ], [ 'mstore', i, add(['mload', i], sub(['mload', c], 127)) ], [ 'mstore', data_pos, add(['mload', data_pos], sub(['mload', c], 96)) ] ], [ 'if', ['lt', ['mload', c], 192], [ 'seq', [ 'mstore', L, call_data_bytes_as_int( add(['mload', i], 1), sub(['mload', c], 183)) ], [ 'assert', [ 'mul', call_data_char( add(['mload', i], 1)), ['ge', ['mload', L], 56] ] ], [ 'mstore', add(data, ['mload', data_pos]), ['mload', L] ], [ 'calldatacopy', add(data + 32, ['mload', data_pos]), add(['mload', i], sub(['mload', c], 182)), ['mload', L] ], [ 'mstore', i, add( add(['mload', i], sub(['mload', c], 182)), ['mload', L]) ], [ 'mstore', data_pos, add(['mload', data_pos], add(['mload', L], 32)) ] ], ['invalid'] ] ] ], ] ], ['assert', ['le', ['mload', position_index], 31]], [ 'mstore', position_offset, add(['mul', ['mload', position_index], 32], 32) ], ['mstore', i, sub(['mload', position_offset], 32)], [ 'repeat', MemoryPositions.FREE_LOOP_INDEX, 1, 100, [ 'seq', ['if', ['slt', ['mload', i], 0], 'break'], [ 'mstore', add(sub(data, ['mload', position_offset]), ['mload', i]), add(['mload', add(positions, ['mload', i])], ['mload', position_offset]) ], # ~mstore(data - positionOffset + i, ~mload(positions + i) + positionOffset) ['mstore', i, sub(['mload', i], 32)], ] ], [ 'mstore', sub(data, 32), add(['mload', position_offset], ['mload', data_pos]) ], [ 'return', sub(data, ['mload', position_offset]), add(['mload', position_offset], ['mload', data_pos]) ] ], [0] ] ] ])