def _slice(expr, args, kwargs, context): sub, start, length = args[0], kwargs['start'], kwargs['len'] if not are_units_compatible(start.typ, BaseType("num")): 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("num")): 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) # New maximum length in the type of the result newmaxlen = length.value if not len(length.args) else sub.typ.maxlen out = ['with', '_start', start, ['with', '_length', length, ['with', '_opos', ['add', placeholder_node, ['mod', '_start', 32]], ['seq', ['assert', ['lt', ['add', '_start', '_length'], sub.typ.maxlen]], copier, ['mstore', '_opos', '_length'], '_opos']]]] return LLLnode.from_list(out, typ=ByteArrayType(newmaxlen), location='memory', 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 test_sha3_32(): lll = ['sha3_32', 0] evm = [ 'PUSH1', 0, 'PUSH1', 192, 'MSTORE', 'PUSH1', 32, 'PUSH1', 192, 'SHA3' ] assert compile_lll.compile_to_assembly(LLLnode.from_list(lll)) == evm assert compile_lll.compile_to_assembly( optimizer.optimize(LLLnode.from_list(lll))) == evm
def as_num256(expr, args, kwargs, context): if isinstance(args[0], int): if not(0 <= args[0] <= 2**256 - 1): raise InvalidLiteralException("Number out of range: " + str(expr.args[0].n), expr.args[0]) return LLLnode.from_list(args[0], typ=BaseType('num256'), pos=getpos(expr)) elif isinstance(args[0], LLLnode): return LLLnode.from_list(['clampge', args[0], 0], typ=BaseType('num256'), pos=getpos(expr)) else: raise InvalidLiteralException("Invalid input for num256: %r" % args[0], 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 ecmul(expr, args, kwargs, context): placeholder_node = LLLnode.from_list( context.new_placeholder(ByteArrayType(128)), typ=ByteArrayType(128), location='memory' ) o = LLLnode.from_list(['seq', ['mstore', placeholder_node, avo(args[0], 0)], ['mstore', ['add', placeholder_node, 32], avo(args[0], 1)], ['mstore', ['add', placeholder_node, 64], args[1]], ['assert', ['call', 40000, 7, 0, placeholder_node, 96, placeholder_node, 64]], placeholder_node], typ=ListType(BaseType('num256'), 2), pos=getpos(expr), location='memory') return o
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 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))
def minmax(expr, args, kwargs, context, is_min): 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 == 'num256': 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 elif left.typ.typ == 'num' and right.typ.typ == 'decimal': o = [ 'if', [comparator, ['mul', '_l', DECIMAL_DIVISOR], '_r'], '_r', ['mul', '_l', DECIMAL_DIVISOR] ] otyp = 'decimal' elif left.typ.typ == 'decimal' and right.typ.typ == 'num': o = [ 'if', [comparator, '_l', ['mul', '_r', DECIMAL_DIVISOR]], ['mul', '_r', DECIMAL_DIVISOR], '_l' ] otyp = 'decimal' 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 as_wei_value(expr, args, kwargs, context): # Denominations if args[1] == "wei": denomination = 1 elif args[1] in ("kwei", "ada", "lovelace"): denomination = 10**3 elif args[1] == "babbage": denomination = 10**6 elif args[1] in ("shannon", "gwei"): denomination = 10**9 elif args[1] == "szabo": denomination = 10**12 elif args[1] == "finney": denomination = 10**15 elif args[1] == "ether": denomination = 10**18 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.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))
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 decimal(expr, args, kwargs, context): if args[0].typ.typ == 'decimal': return args[0] else: return LLLnode.from_list( ['mul', args[0], DECIMAL_DIVISOR], typ=BaseType('decimal', args[0].typ.unit, args[0].typ.positional), 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('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 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_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 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 concat(expr, context): from viper.parser.parser import parse_expr, unwrap_location args = [parse_expr(arg, context) 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 as_num256(expr, args, kwargs, context): if isinstance(args[0], int): if not(0 <= args[0] <= 2**256 - 1): raise InvalidLiteralException("Number out of range: " + str(expr.args[0].n), expr.args[0]) return LLLnode.from_list(args[0], typ=BaseType('num256', None), pos=getpos(expr)) elif isinstance(args[0], LLLnode): if args[0].value == "sub" and args[0].args[0].value == 0 and args[0].args[1].value > 0: raise InvalidLiteralException("Negative numbers cannot be num256 literals") return LLLnode(value=args[0].value, args=args[0].args, typ=BaseType('num256'), pos=getpos(expr)) else: raise InvalidLiteralException("Invalid input for num256: %r" % args[0], expr)
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', ['sle', '_s', 0], ['div', '_v', ['exp', 2, ['sub', 0, '_s']]], ['mul', '_v', ['exp', 2, '_s']]]]], typ=BaseType('num256'), pos=getpos(expr))
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 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 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 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
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 create_with_code_of(expr, args, kwargs, context): value = kwargs['value'] if value != zero_value: enforce_units(value.typ, get_keyword(expr, 'value'), BaseType('num', {'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 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 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)
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', loop_memory_position, 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', loop_memory_position, 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] ] ] ])
def num256_le(expr, args, kwargs, context): return LLLnode.from_list(['le', args[0], args[1]], typ=BaseType('bool'), pos=getpos(expr))
def bitwise_not(expr, args, kwargs, context): return LLLnode.from_list(['not', args[0]], typ=BaseType('num256'), pos=getpos(expr))