Exemple #1
0
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))
Exemple #2
0
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))
Exemple #3
0
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))
Exemple #4
0
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))
Exemple #5
0
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)
Exemple #6
0
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))
Exemple #7
0
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))
Exemple #8
0
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))
Exemple #9
0
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))
Exemple #10
0
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) and args[0].typ.typ in ('num', 'num_literal', 'address'):
        return LLLnode.from_list(['clampge', args[0], 0],
                                 typ=BaseType('num256'),
                                 pos=getpos(expr))
    elif isinstance(args[0], LLLnode):
        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)
Exemple #11
0
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))
Exemple #12
0
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
Exemple #13
0
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))
Exemple #14
0
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))
Exemple #15
0
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
Exemple #16
0
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))
Exemple #17
0
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))
Exemple #18
0
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))
Exemple #19
0
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))
Exemple #20
0
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))
Exemple #21
0
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
Exemple #22
0
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))
Exemple #23
0
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))
Exemple #24
0
def bitwise_not(expr, args, kwargs, context):
    return LLLnode.from_list(['not', args[0]], typ=BaseType('num256'), pos=getpos(expr))
Exemple #25
0
def num256_mod(expr, args, kwargs, context):
    return LLLnode.from_list(['seq',
                                ['assert', args[1]],
                                ['mod', args[0], args[1]]], typ=BaseType('num256'), pos=getpos(expr))
Exemple #26
0
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)
    )
Exemple #27
0
def num256_le(expr, args, kwargs, context):
    return LLLnode.from_list(['le', args[0], args[1]], typ=BaseType('bool'), pos=getpos(expr))
Exemple #28
0
def as_bytes32(expr, args, kwargs, context):
    return LLLnode(value=args[0].value, args=args[0].args, typ=BaseType('bytes32'), pos=getpos(expr))
Exemple #29
0
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))
Exemple #30
0
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), annotation='concat'
    )