コード例 #1
0
ファイル: parser.py プロジェクト: DadiaoMoe/ophydia
def make_clamper(datapos, mempos, typ, is_init=False):
    if not is_init:
        data_decl = ['calldataload', ['add', 4, datapos]]
        copier = lambda pos, sz: ['calldatacopy', mempos, ['add', 4, pos], sz]
    else:
        data_decl = ['codeload', ['add', '~codelen', datapos]]
        copier = lambda pos, sz: [
            'codecopy', mempos, ['add', '~codelen', pos], sz
        ]
    # Numbers: make sure they're in range
    if is_base_type(typ, 'int128'):
        return LLLnode.from_list([
            'clamp', ['mload', MemoryPositions.MINNUM], data_decl,
            ['mload', MemoryPositions.MAXNUM]
        ],
                                 typ=typ,
                                 annotation='checking int128 input')
    # Booleans: make sure they're zero or one
    elif is_base_type(typ, 'bool'):
        return LLLnode.from_list(['uclamplt', data_decl, 2],
                                 typ=typ,
                                 annotation='checking bool input')
    # Addresses: make sure they're in range
    elif is_base_type(typ, 'address'):
        return LLLnode.from_list(
            ['uclamplt', data_decl, ['mload', MemoryPositions.ADDRSIZE]],
            typ=typ,
            annotation='checking address input')
    # Bytes: make sure they have the right size
    elif isinstance(typ, ByteArrayType):
        return LLLnode.from_list([
            'seq',
            copier(data_decl, 32 + typ.maxlen),
            [
                'assert',
                ['le', ['calldataload', ['add', 4, data_decl]], typ.maxlen]
            ]
        ],
                                 typ=None,
                                 annotation='checking bytearray input')
    # Lists: recurse
    elif isinstance(typ, ListType):
        o = []
        for i in range(typ.count):
            offset = get_size_of_type(typ.subtype) * 32 * i
            o.append(
                make_clamper(datapos + offset, mempos + offset, typ.subtype,
                             is_init))
        return LLLnode.from_list(['seq'] + o,
                                 typ=None,
                                 annotation='checking list input')
    # Otherwise don't make any checks
    else:
        return LLLnode.from_list('pass')
コード例 #2
0
ファイル: self_call.py プロジェクト: DadiaoMoe/ophydia
def call_make_placeholder(stmt_expr, context, sig):
    if sig.output_type is None:
        return 0, 0, 0

    output_placeholder = context.new_placeholder(typ=sig.output_type)
    out_size = get_size_of_type(sig.output_type) * 32
    returner = output_placeholder

    if not sig.private and isinstance(sig.output_type, ByteArrayType):
        returner = output_placeholder + 32

    return output_placeholder, returner, out_size
コード例 #3
0
ファイル: context.py プロジェクト: DadiaoMoe/ophydia
 def new_variable(self, name, typ):
     if not is_varname_valid(name, custom_units=self.custom_units):
         raise VariableDeclarationException(
             "Variable name invalid or reserved: " + name)
     if any((name in self.vars, name in self.globals, name
             in self.constants)):
         raise VariableDeclarationException("Duplicate variable name: %s" %
                                            name)
     self.vars[name] = VariableRecord(name, self.next_mem, typ, True,
                                      self.blockscopes.copy())
     pos = self.next_mem
     self.next_mem += 32 * get_size_of_type(typ)
     return pos
コード例 #4
0
ファイル: parser.py プロジェクト: DadiaoMoe/ophydia
def get_external_contract_call_output(sig, context):
    if not sig.output_type:
        return 0, 0, []
    output_placeholder = context.new_placeholder(typ=sig.output_type)
    output_size = get_size_of_type(sig.output_type) * 32
    if isinstance(sig.output_type, BaseType):
        returner = [0, output_placeholder]
    elif isinstance(sig.output_type, ByteArrayType):
        returner = [0, output_placeholder + 32]
    else:
        raise TypeMismatchException("Invalid output type: %s" %
                                    sig.output_type)
    return output_placeholder, output_size, returner
コード例 #5
0
ファイル: event_signature.py プロジェクト: DadiaoMoe/ophydia
    def from_declaration(cls, code, custom_units=None):
        name = code.target.id
        pos = 0

        if not is_varname_valid(name, custom_units=custom_units):
            raise EventDeclarationException("Event name invalid: " + name)
        # Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ...
        args = []
        indexed_list = []
        topics_count = 1
        if code.annotation.args:
            keys = code.annotation.args[0].keys
            values = code.annotation.args[0].values
            for i in range(len(keys)):
                typ = values[i]
                arg = keys[i].id
                is_indexed = False
                # Check to see if argument is a topic
                if isinstance(typ, ast.Call) and typ.func.id == 'indexed':
                    typ = values[i].args[0]
                    indexed_list.append(True)
                    topics_count += 1
                    is_indexed = True
                else:
                    indexed_list.append(False)
                if isinstance(typ, ast.Subscript) and getattr(typ.value, 'id', None) == 'bytes' and typ.slice.value.n > 32 and is_indexed:
                    raise EventDeclarationException("Indexed arguments are limited to 32 bytes")
                if topics_count > 4:
                    raise EventDeclarationException("Maximum of 3 topics {} given".format(topics_count - 1), arg)
                if not isinstance(arg, str):
                    raise VariableDeclarationException("Argument name invalid", arg)
                if not typ:
                    raise InvalidTypeException("Argument must have type", arg)
                if not is_varname_valid(arg, custom_units):
                    raise VariableDeclarationException("Argument name invalid or reserved: " + arg, arg)
                if arg in (x.name for x in args):
                    raise VariableDeclarationException("Duplicate function argument name: " + arg, arg)
                parsed_type = parse_type(typ, None, custom_units=custom_units)
                args.append(VariableRecord(arg, pos, parsed_type, False))
                if isinstance(parsed_type, ByteArrayType):
                    pos += ceil32(typ.slice.value.n)
                else:
                    pos += get_size_of_type(parsed_type) * 32
        sig = name + '(' + ','.join([canonicalize_type(arg.typ, indexed_list[pos]) for pos, arg in enumerate(args)]) + ')'  # noqa F812
        event_id = bytes_to_int(sha3(bytes(sig, 'utf-8')))
        return cls(name, args, indexed_list, event_id, sig)
コード例 #6
0
ファイル: functions.py プロジェクト: DadiaoMoe/ophydia
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,
                ('int128', 'uint256', '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 uint256
        elif is_base_type(typ, ('int128', 'uint256')):
            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:
            # Should never reach because of top level base level check.
            raise Exception("Type not yet supported")  # pragma: no cover
    # 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:
        # Should never reach because of top level base level check.
        raise Exception("Location not yet supported")  # pragma: no cover
    # 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))
コード例 #7
0
ファイル: parser_utils.py プロジェクト: DadiaoMoe/ophydia
def make_setter(left, right, location, pos):
    # Basic types
    if isinstance(left.typ, BaseType):
        right = base_type_conversion(right, right.typ, left.typ, pos)
        if location == 'storage':
            return LLLnode.from_list(['sstore', left, right], typ=None)
        elif location == 'memory':
            return LLLnode.from_list(['mstore', left, right], typ=None)
    # Byte arrays
    elif isinstance(left.typ, ByteArrayType):
        return make_byte_array_copier(left, right, pos)
    # Can't copy mappings
    elif isinstance(left.typ, MappingType):
        raise TypeMismatchException(
            "Cannot copy mappings; can only copy individual elements", pos)
    # Arrays
    elif isinstance(left.typ, ListType):
        # Cannot do something like [a, b, c] = [1, 2, 3]
        if left.value == "multi":
            raise Exception("Target of set statement must be a single item")
        if not isinstance(right.typ, (ListType, NullType)):
            raise TypeMismatchException(
                "Setter type mismatch: left side is array, right side is %r" %
                right.typ, pos)
        left_token = LLLnode.from_list('_L',
                                       typ=left.typ,
                                       location=left.location)
        if left.location == "storage":
            left = LLLnode.from_list(['sha3_32', left],
                                     typ=left.typ,
                                     location="storage_prehashed")
            left_token.location = "storage_prehashed"
        # Type checks
        if not isinstance(right.typ, NullType):
            if not isinstance(right.typ, ListType):
                raise TypeMismatchException(
                    "Left side is array, right side is not", pos)
            if left.typ.count != right.typ.count:
                raise TypeMismatchException("Mismatched number of elements",
                                            pos)
        # If the right side is a literal
        if right.value == "multi":
            if len(right.args) != left.typ.count:
                raise TypeMismatchException("Mismatched number of elements",
                                            pos)
            subs = []
            for i in range(left.typ.count):
                subs.append(
                    make_setter(add_variable_offset(left_token,
                                                    LLLnode.from_list(
                                                        i, typ='int128'),
                                                    pos=pos),
                                right.args[i],
                                location,
                                pos=pos))
            return LLLnode.from_list(['with', '_L', left, ['seq'] + subs],
                                     typ=None)
        # If the right side is a null
        elif isinstance(right.typ, NullType):
            subs = []
            for i in range(left.typ.count):
                subs.append(
                    make_setter(add_variable_offset(left_token,
                                                    LLLnode.from_list(
                                                        i, typ='int128'),
                                                    pos=pos),
                                LLLnode.from_list(None, typ=NullType()),
                                location,
                                pos=pos))
            return LLLnode.from_list(['with', '_L', left, ['seq'] + subs],
                                     typ=None)
        # If the right side is a variable
        else:
            right_token = LLLnode.from_list('_R',
                                            typ=right.typ,
                                            location=right.location)
            subs = []
            for i in range(left.typ.count):
                subs.append(
                    make_setter(
                        add_variable_offset(left_token,
                                            LLLnode.from_list(i, typ='int128'),
                                            pos=pos),
                        add_variable_offset(right_token,
                                            LLLnode.from_list(i, typ='int128'),
                                            pos=pos),
                        location,
                        pos=pos))
            return LLLnode.from_list(
                ['with', '_L', left, ['with', '_R', right, ['seq'] + subs]],
                typ=None)
    # Structs
    elif isinstance(left.typ, (StructType, TupleType)):
        if left.value == "multi" and isinstance(left.typ, StructType):
            raise Exception("Target of set statement must be a single item")
        if not isinstance(right.typ, NullType):
            if not isinstance(right.typ, left.typ.__class__):
                raise TypeMismatchException(
                    "Setter type mismatch: left side is %r, right side is %r" %
                    (left.typ, right.typ), pos)
            if isinstance(left.typ, StructType):
                for k in left.typ.members:
                    if k not in right.typ.members:
                        raise TypeMismatchException(
                            "Keys don't match for structs, missing %s" % k,
                            pos)
                for k in right.typ.members:
                    if k not in left.typ.members:
                        raise TypeMismatchException(
                            "Keys don't match for structs, extra %s" % k, pos)
            else:
                if len(left.typ.members) != len(right.typ.members):
                    raise TypeMismatchException(
                        "Tuple lengths don't match, %d vs %d" %
                        (len(left.typ.members), len(right.typ.members)), pos)
        left_token = LLLnode.from_list('_L',
                                       typ=left.typ,
                                       location=left.location)
        if left.location == "storage":
            left = LLLnode.from_list(['sha3_32', left],
                                     typ=left.typ,
                                     location="storage_prehashed")
            left_token.location = "storage_prehashed"
        if isinstance(left.typ, StructType):
            keyz = sorted(list(left.typ.members.keys()))
        else:
            keyz = list(range(len(left.typ.members)))
        # If the right side is a literal
        if right.value == "multi":
            if len(right.args) != len(keyz):
                raise TypeMismatchException("Mismatched number of elements",
                                            pos)
            subs = []
            for i, typ in enumerate(keyz):
                subs.append(
                    make_setter(add_variable_offset(left_token, typ, pos=pos),
                                right.args[i],
                                location,
                                pos=pos))
            return LLLnode.from_list(['with', '_L', left, ['seq'] + subs],
                                     typ=None)
        # If the right side is a null
        elif isinstance(right.typ, NullType):
            subs = []
            for typ in keyz:
                subs.append(
                    make_setter(add_variable_offset(left_token, typ, pos=pos),
                                LLLnode.from_list(None, typ=NullType()),
                                location,
                                pos=pos))
            return LLLnode.from_list(['with', '_L', left, ['seq'] + subs],
                                     typ=None)
        # If tuple assign.
        elif isinstance(left.typ, TupleType) and isinstance(
                right.typ, TupleType):
            right_token = LLLnode.from_list('_R',
                                            typ=right.typ,
                                            location="memory")
            subs = []
            static_offset_counter = 0
            for idx, (left_arg,
                      right_arg) in enumerate(zip(left.args,
                                                  right.typ.members)):
                # if left_arg.typ.typ != right_arg.typ:
                #     raise TypeMismatchException("Tuple assignment mismatch position %d, expected '%s'" % (idx, right.typ), pos)
                if isinstance(right_arg, ByteArrayType):
                    offset = LLLnode.from_list([
                        'add', '_R',
                        ['mload', ['add', '_R', static_offset_counter]]
                    ],
                                               typ=ByteArrayType(
                                                   right_arg.maxlen),
                                               location='memory',
                                               pos=pos)
                    static_offset_counter += 32
                else:
                    offset = LLLnode.from_list(
                        ['mload', ['add', '_R', static_offset_counter]],
                        typ=right_arg.typ,
                        pos=pos)
                    static_offset_counter += get_size_of_type(right_arg) * 32
                subs.append(
                    make_setter(left_arg, offset, location="memory", pos=pos))
            return LLLnode.from_list(['with', '_R', right, ['seq'] + subs],
                                     typ=None,
                                     annotation='Tuple assignment')
        # If the right side is a variable
        else:
            subs = []
            right_token = LLLnode.from_list('_R',
                                            typ=right.typ,
                                            location=right.location)
            for typ in keyz:
                subs.append(
                    make_setter(add_variable_offset(left_token, typ, pos=pos),
                                add_variable_offset(right_token, typ, pos=pos),
                                location,
                                pos=pos))
            return LLLnode.from_list(
                ['with', '_L', left, ['with', '_R', right, ['seq'] + subs]],
                typ=None)
    else:
        raise Exception("Invalid type for setters")
コード例 #8
0
ファイル: parser_utils.py プロジェクト: DadiaoMoe/ophydia
def pack_arguments(signature, args, context, pos, return_placeholder=True):
    placeholder_typ = ByteArrayType(
        maxlen=sum([get_size_of_type(arg.typ)
                    for arg in signature.args]) * 32 + 32)
    placeholder = context.new_placeholder(placeholder_typ)
    setters = [['mstore', placeholder, signature.method_id]]
    needpos = False
    staticarray_offset = 0
    expected_arg_count = len(signature.args)
    actual_arg_count = len(args)
    if actual_arg_count != expected_arg_count:
        raise StructureException(
            "Wrong number of args for: %s (%s args, expected %s)" %
            (signature.name, actual_arg_count, expected_arg_count))

    for i, (arg,
            typ) in enumerate(zip(args, [arg.typ for arg in signature.args])):
        if isinstance(typ, BaseType):
            setters.append(
                make_setter(LLLnode.from_list(placeholder +
                                              staticarray_offset + 32 + i * 32,
                                              typ=typ),
                            arg,
                            'memory',
                            pos=pos))
        elif isinstance(typ, ByteArrayType):
            setters.append([
                'mstore', placeholder + staticarray_offset + 32 + i * 32,
                '_poz'
            ])
            arg_copy = LLLnode.from_list('_s',
                                         typ=arg.typ,
                                         location=arg.location)
            target = LLLnode.from_list(['add', placeholder + 32, '_poz'],
                                       typ=typ,
                                       location='memory')
            setters.append([
                'with', '_s', arg,
                [
                    'seq',
                    make_byte_array_copier(target, arg_copy, pos),
                    [
                        'set', '_poz',
                        [
                            'add', 32,
                            ['ceil32', ['add', '_poz',
                                        get_length(arg_copy)]]
                        ]
                    ]
                ]
            ])
            needpos = True
        elif isinstance(typ, ListType):
            target = LLLnode.from_list(
                [placeholder + 32 + staticarray_offset + i * 32],
                typ=typ,
                location='memory')
            setters.append(make_setter(target, arg, 'memory', pos=pos))
            staticarray_offset += 32 * (typ.count - 1)
        else:
            raise TypeMismatchException("Cannot pack argument of type %r" %
                                        typ)

    # For private call usage, doesn't use a returner.
    returner = [[placeholder + 28]] if return_placeholder else []
    if needpos:
        return (LLLnode.from_list([
            'with', '_poz',
            len(args) * 32 + staticarray_offset, ['seq'] + setters + returner
        ],
                                  typ=placeholder_typ,
                                  location='memory'),
                placeholder_typ.maxlen - 28, placeholder + 32)
    else:
        return (LLLnode.from_list(['seq'] + setters + returner,
                                  typ=placeholder_typ,
                                  location='memory'),
                placeholder_typ.maxlen - 28, placeholder + 32)
コード例 #9
0
ファイル: parser_utils.py プロジェクト: DadiaoMoe/ophydia
def add_variable_offset(parent, key, pos):
    typ, location = parent.typ, parent.location
    if isinstance(typ, (StructType, TupleType)):
        if isinstance(typ, StructType):
            if not isinstance(key, str):
                raise TypeMismatchException(
                    "Expecting a member variable access; cannot access element %r"
                    % key, pos)
            if key not in typ.members:
                raise TypeMismatchException(
                    "Object does not have member variable %s" % key, pos)
            subtype = typ.members[key]
            attrs = sorted(typ.members.keys())

            if key not in attrs:
                raise TypeMismatchException(
                    "Member %s not found. Only the following available: %s" %
                    (key, " ".join(attrs)), pos)
            index = attrs.index(key)
            annotation = key
        else:
            if not isinstance(key, int):
                raise TypeMismatchException(
                    "Expecting a static index; cannot access element %r" % key,
                    pos)
            attrs = list(range(len(typ.members)))
            index = key
            annotation = None
        if location == 'storage':
            return LLLnode.from_list([
                'add', ['sha3_32', parent],
                LLLnode.from_list(index, annotation=annotation)
            ],
                                     typ=subtype,
                                     location='storage')
        elif location == 'storage_prehashed':
            return LLLnode.from_list([
                'add', parent,
                LLLnode.from_list(index, annotation=annotation)
            ],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            offset = 0
            for i in range(index):
                offset += 32 * get_size_of_type(typ.members[attrs[i]])
            return LLLnode.from_list(['add', offset, parent],
                                     typ=typ.members[key],
                                     location='memory',
                                     annotation=annotation)
        else:
            raise TypeMismatchException(
                "Not expecting a member variable access")

    elif isinstance(typ, MappingType):

        if isinstance(key.typ, ByteArrayType):
            if not isinstance(typ.keytype, ByteArrayType) or (
                    typ.keytype.maxlen < key.typ.maxlen):
                raise TypeMismatchException(
                    'Mapping keys of bytes cannot be cast, use exact same bytes type of: %s'
                    % str(typ.keytype), pos)
            subtype = typ.valuetype
            if len(key.args[0].args) >= 3:  # handle bytes literal.
                sub = LLLnode.from_list([
                    'seq', key,
                    [
                        'sha3', ['add', key.args[0].args[-1], 32],
                        ['mload', key.args[0].args[-1]]
                    ]
                ])
            else:
                sub = LLLnode.from_list([
                    'sha3', ['add', key.args[0].value, 32],
                    ['mload', key.args[0].value]
                ])
        else:
            subtype = typ.valuetype
            sub = base_type_conversion(key, key.typ, typ.keytype, pos=pos)

        if location == 'storage':
            return LLLnode.from_list(['sha3_64', parent, sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            raise TypeMismatchException(
                "Can only have fixed-side arrays in memory, not mappings", pos)

    elif isinstance(typ, ListType):

        subtype = typ.subtype
        sub = [
            'uclamplt',
            base_type_conversion(key, key.typ, BaseType('int128'), pos=pos),
            typ.count
        ]

        if location == 'storage':
            return LLLnode.from_list(['add', ['sha3_32', parent], sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'storage_prehashed':
            return LLLnode.from_list(['add', parent, sub],
                                     typ=subtype,
                                     location='storage')
        elif location == 'memory':
            offset = 32 * get_size_of_type(subtype)
            return LLLnode.from_list(['add', ['mul', offset, sub], parent],
                                     typ=subtype,
                                     location='memory')
        else:
            raise TypeMismatchException("Not expecting an array access ", pos)
    else:
        raise TypeMismatchException(
            "Cannot access the child of a constant variable! %r" % typ, pos)
コード例 #10
0
ファイル: parser.py プロジェクト: DadiaoMoe/ophydia
def parse_func(code, sigs, origcode, global_ctx, _vars=None):
    if _vars is None:
        _vars = {}
    sig = FunctionSignature.from_definition(
        code, sigs=sigs, custom_units=global_ctx._custom_units)
    # Get base args for function.
    total_default_args = len(code.args.defaults)
    base_args = sig.args[:
                         -total_default_args] if total_default_args > 0 else sig.args
    default_args = code.args.args[-total_default_args:]
    default_values = dict(
        zip([arg.arg for arg in default_args], code.args.defaults))
    # __init__ function may not have defaults.
    if sig.name == '__init__' and total_default_args > 0:
        raise FunctionDeclarationException(
            "__init__ function may not have default parameters.")
    # Check for duplicate variables with globals
    for arg in sig.args:
        if arg.name in global_ctx._globals:
            raise FunctionDeclarationException(
                "Variable name duplicated between function arguments and globals: "
                + arg.name)

    # Create a local (per function) context.
    context = Context(vars=_vars,
                      global_ctx=global_ctx,
                      sigs=sigs,
                      return_type=sig.output_type,
                      is_constant=sig.const,
                      is_payable=sig.payable,
                      origcode=origcode,
                      is_private=sig.private,
                      method_id=sig.method_id)

    # Copy calldata to memory for fixed-size arguments
    max_copy_size = sum([
        32 if isinstance(arg.typ, ByteArrayType) else
        get_size_of_type(arg.typ) * 32 for arg in sig.args
    ])
    base_copy_size = sum([
        32 if isinstance(arg.typ, ByteArrayType) else
        get_size_of_type(arg.typ) * 32 for arg in base_args
    ])
    context.next_mem += max_copy_size

    clampers = []

    # Create callback_ptr, this stores a destination in the bytecode for a private
    # function to jump to after a function has executed.
    _post_callback_ptr = "{}_{}_post_callback_ptr".format(
        sig.name, sig.method_id)
    if sig.private:
        context.callback_ptr = context.new_placeholder(typ=BaseType('uint256'))
        clampers.append(
            LLLnode.from_list(['mstore', context.callback_ptr, 'pass'],
                              annotation='pop callback pointer'))
        if total_default_args > 0:
            clampers.append(['label', _post_callback_ptr])

    # private functions without return types need to jump back to
    # the calling function, as there is no return statement to handle the
    # jump.
    stop_func = [['stop']]
    if sig.output_type is None and sig.private:
        stop_func = [['jump', ['mload', context.callback_ptr]]]

    if not len(base_args):
        copier = 'pass'
    elif sig.name == '__init__':
        copier = [
            'codecopy', MemoryPositions.RESERVED_MEMORY, '~codelen',
            base_copy_size
        ]
    else:
        copier = get_arg_copier(sig=sig,
                                total_size=base_copy_size,
                                memory_dest=MemoryPositions.RESERVED_MEMORY)
    clampers.append(copier)

    # Add asserts for payable and internal
    # private never gets payable check.
    if not sig.payable and not sig.private:
        clampers.append(['assert', ['iszero', 'callvalue']])

    # Fill variable positions
    for i, arg in enumerate(sig.args):
        if i < len(base_args) and not sig.private:
            clampers.append(
                make_clamper(arg.pos, context.next_mem, arg.typ,
                             sig.name == '__init__'))
        if isinstance(arg.typ, ByteArrayType):
            context.vars[arg.name] = VariableRecord(arg.name, context.next_mem,
                                                    arg.typ, False)
            context.next_mem += 32 * get_size_of_type(arg.typ)
        else:
            context.vars[arg.name] = VariableRecord(
                arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ,
                False)

    # Private function copiers. No clamping for private functions.
    dyn_variable_names = [
        a.name for a in base_args if isinstance(a.typ, ByteArrayType)
    ]
    if sig.private and dyn_variable_names:
        i_placeholder = context.new_placeholder(typ=BaseType('uint256'))
        unpackers = []
        for idx, var_name in enumerate(dyn_variable_names):
            var = context.vars[var_name]
            ident = "_load_args_%d_dynarg%d" % (sig.method_id, idx)
            o = make_unpacker(ident=ident,
                              i_placeholder=i_placeholder,
                              begin_pos=var.pos)
            unpackers.append(o)

        if not unpackers:
            unpackers = ['pass']

        clampers.append(
            LLLnode.from_list(
                ['seq_unchecked'] + unpackers + [
                    0
                ],  # [0] to complete full overarching 'seq' statement, see private_label.
                typ=None,
                annotation='dynamic unpacker',
                pos=getpos(code)))

    # Create "clampers" (input well-formedness checkers)
    # Return function body
    if sig.name == '__init__':
        o = LLLnode.from_list(['seq'] + clampers +
                              [parse_body(code.body, context)],
                              pos=getpos(code))
    elif is_default_func(sig):
        if len(sig.args) > 0:
            raise FunctionDeclarationException(
                'Default function may not receive any arguments.', code)
        if sig.private:
            raise FunctionDeclarationException(
                'Default function may only be public.', code)
        o = LLLnode.from_list(['seq'] + clampers +
                              [parse_body(code.body, context)],
                              pos=getpos(code))
    else:

        if total_default_args > 0:  # Function with default parameters.
            function_routine = "{}_{}".format(sig.name, sig.method_id)
            default_sigs = generate_default_arg_sigs(code, sigs,
                                                     global_ctx._custom_units)
            sig_chain = ['seq']

            for default_sig in default_sigs:
                sig_compare, private_label = get_sig_statements(
                    default_sig, getpos(code))

                # Populate unset default variables
                populate_arg_count = len(sig.args) - len(default_sig.args)
                set_defaults = []
                if populate_arg_count > 0:
                    current_sig_arg_names = {x.name for x in default_sig.args}
                    missing_arg_names = [
                        arg.arg for arg in default_args
                        if arg.arg not in current_sig_arg_names
                    ]
                    for arg_name in missing_arg_names:
                        value = Expr(default_values[arg_name],
                                     context).lll_node
                        var = context.vars[arg_name]
                        left = LLLnode.from_list(var.pos,
                                                 typ=var.typ,
                                                 location='memory',
                                                 pos=getpos(code),
                                                 mutable=var.mutable)
                        set_defaults.append(
                            make_setter(left,
                                        value,
                                        'memory',
                                        pos=getpos(code)))

                current_sig_arg_names = {x.name for x in default_sig.args}
                base_arg_names = {arg.name for arg in base_args}
                if sig.private:
                    # Load all variables in default section, if private,
                    # because the stack is a linear pipe.
                    copier_arg_count = len(default_sig.args)
                    copier_arg_names = current_sig_arg_names
                else:
                    copier_arg_count = len(default_sig.args) - len(base_args)
                    copier_arg_names = current_sig_arg_names - base_arg_names
                # Order copier_arg_names, this is very important.
                copier_arg_names = [
                    x.name for x in default_sig.args
                    if x.name in copier_arg_names
                ]

                # Variables to be populated from calldata/stack.
                default_copiers = []
                if copier_arg_count > 0:
                    # Get map of variables in calldata, with thier offsets
                    offset = 4
                    calldata_offset_map = {}
                    for arg in default_sig.args:
                        calldata_offset_map[arg.name] = offset
                        offset += 32 if isinstance(
                            arg.typ,
                            ByteArrayType) else get_size_of_type(arg.typ) * 32
                    # Copy set default parameters from calldata
                    dynamics = []
                    for arg_name in copier_arg_names:
                        var = context.vars[arg_name]
                        calldata_offset = calldata_offset_map[arg_name]
                        if sig.private:
                            _offset = calldata_offset
                            if isinstance(var.typ, ByteArrayType):
                                _size = 32
                                dynamics.append(var.pos)
                            else:
                                _size = var.size * 32
                            default_copiers.append(
                                get_arg_copier(sig=sig,
                                               memory_dest=var.pos,
                                               total_size=_size,
                                               offset=_offset))
                        else:
                            # Add clampers.
                            default_copiers.append(
                                make_clamper(calldata_offset - 4, var.pos,
                                             var.typ))
                            # Add copying code.
                            if isinstance(var.typ, ByteArrayType):
                                _offset = [
                                    'add', 4,
                                    ['calldataload', calldata_offset]
                                ]
                            else:
                                _offset = calldata_offset
                            default_copiers.append(
                                get_arg_copier(sig=sig,
                                               memory_dest=var.pos,
                                               total_size=var.size * 32,
                                               offset=_offset))

                    # Unpack byte array if necessary.
                    if dynamics:
                        i_placeholder = context.new_placeholder(
                            typ=BaseType('uint256'))
                        for idx, var_pos in enumerate(dynamics):
                            ident = 'unpack_default_sig_dyn_%d_arg%d' % (
                                default_sig.method_id, idx)
                            default_copiers.append(
                                make_unpacker(ident=ident,
                                              i_placeholder=i_placeholder,
                                              begin_pos=var_pos))
                    default_copiers.append(0)  # for over arching seq, POP

                sig_chain.append([
                    'if', sig_compare,
                    [
                        'seq', private_label,
                        LLLnode.from_list(
                            ['mstore', context.callback_ptr, 'pass'],
                            annotation='pop callback pointer',
                            pos=getpos(code)) if sig.private else ['pass'],
                        ['seq'] + set_defaults if set_defaults else ['pass'],
                        ['seq_unchecked'] +
                        default_copiers if default_copiers else ['pass'],
                        [
                            'goto', _post_callback_ptr
                            if sig.private else function_routine
                        ]
                    ]
                ])

            # With private functions all variable loading occurs in the default
            # function sub routine.
            if sig.private:
                _clampers = [['label', _post_callback_ptr]]
            else:
                _clampers = clampers

            # Function with default parameters.
            o = LLLnode.from_list(
                [
                    'seq',
                    sig_chain,
                    [
                        'if',
                        0,  # can only be jumped into
                        [
                            'seq', ['label', function_routine]
                            if not sig.private else ['pass'],
                            ['seq'] + _clampers +
                            [parse_body(c, context)
                             for c in code.body] + stop_func
                        ]
                    ]
                ],
                typ=None,
                pos=getpos(code))

        else:
            # Function without default parameters.
            sig_compare, private_label = get_sig_statements(sig, getpos(code))
            o = LLLnode.from_list([
                'if', sig_compare, ['seq'] + [private_label] + clampers +
                [parse_body(c, context) for c in code.body] + stop_func
            ],
                                  typ=None,
                                  pos=getpos(code))

    # Check for at leasts one return statement if necessary.
    if context.return_type and context.function_return_count == 0:
        raise FunctionDeclarationException(
            "Missing return statement in function '%s' " % sig.name, code)

    o.context = context
    o.total_gas = o.gas + calc_mem_gas(o.context.next_mem)
    o.func_name = sig.name
    return o
コード例 #11
0
    def from_definition(cls,
                        code,
                        sigs=None,
                        custom_units=None,
                        contract_def=False,
                        constant=False):
        name = code.name
        pos = 0

        if not is_varname_valid(name, custom_units=custom_units):
            raise FunctionDeclarationException("Function name invalid: " +
                                               name)
        # Determine the arguments, expects something of the form def foo(arg1: int128, arg2: int128 ...
        args = []
        for arg in code.args.args:
            typ = arg.annotation
            if not typ:
                raise InvalidTypeException("Argument must have type", arg)
            if not is_varname_valid(arg.arg, custom_units=custom_units):
                raise FunctionDeclarationException(
                    "Argument name invalid or reserved: " + arg.arg, arg)
            if arg.arg in (x.name for x in args):
                raise FunctionDeclarationException(
                    "Duplicate function argument name: " + arg.arg, arg)
            parsed_type = parse_type(typ,
                                     None,
                                     sigs,
                                     custom_units=custom_units)
            args.append(VariableRecord(arg.arg, pos, parsed_type, False))
            if isinstance(parsed_type, ByteArrayType):
                pos += 32
            else:
                pos += get_size_of_type(parsed_type) * 32

        # Apply decorators
        const, payable, private, public = False, False, False, False
        for dec in code.decorator_list:
            if isinstance(dec, ast.Name) and dec.id == "constant":
                const = True
            # TODO:
            # elif isinstance(dec, ast.Name) and dec.id == "payable":
            #     payable = True
            elif isinstance(dec, ast.Name) and dec.id == "private":
                private = True
            elif isinstance(dec, ast.Name) and dec.id == "public":
                public = True
            else:
                raise StructureException("Bad decorator", dec)

        if public and private:
            raise StructureException(
                "Cannot use public and private decorators on the same function: {}"
                .format(name))
        # if payable and const:
        #     raise StructureException("Function {} cannot be both constant and payable.".format(name))
        # if payable and private:
        #     raise StructureException("Function {} cannot be both private and payable.".format(name))
        if (not public and not private) and not contract_def:
            raise StructureException(
                "Function visibility must be declared (@public or @private)",
                code)
        if constant:
            const = True
        # Determine the return type and whether or not it's constant. Expects something
        # of the form:
        # def foo(): ...
        # def foo() -> int128: ...
        # If there is no return type, ie. it's of the form def foo(): ...
        # and NOT def foo() -> type: ..., then it's null
        if not code.returns:
            output_type = None
        elif isinstance(
                code.returns,
            (ast.Name, ast.Compare, ast.Subscript, ast.Call, ast.Tuple)):
            output_type = parse_type(code.returns,
                                     None,
                                     sigs,
                                     custom_units=custom_units)
        else:
            raise InvalidTypeException(
                "Output type invalid or unsupported: %r" %
                parse_type(code.returns, None),
                code.returns,
            )
        # Output type must be canonicalizable
        if output_type is not None:
            assert isinstance(output_type,
                              TupleType) or canonicalize_type(output_type)
        # Get the canonical function signature
        sig = cls.get_full_sig(name, code.args.args, sigs, custom_units)

        # Take the first 4 bytes of the hash of the sig to get the method ID
        method_id = fourbytes_to_int(sha3(bytes(sig, 'utf-8'))[:4])
        return cls(name, args, output_type, const, payable, private, sig,
                   method_id, custom_units)
コード例 #12
0
 def size(self):
     return get_size_of_type(self.typ)
コード例 #13
0
ファイル: stmt.py プロジェクト: DadiaoMoe/ophydia
    def parse_return(self):
        if self.context.return_type is None:
            if self.stmt.value:
                raise TypeMismatchException("Not expecting to return a value", self.stmt)
            return LLLnode.from_list(self.make_return_stmt(0, 0), typ=None, pos=getpos(self.stmt))
        if not self.stmt.value:
            raise TypeMismatchException("Expecting to return a value", self.stmt)

        def zero_pad(bytez_placeholder, maxlen):
            zero_padder = LLLnode.from_list(['pass'])
            if maxlen > 0:
                zero_pad_i = self.context.new_placeholder(BaseType('uint256'))  # Iterator used to zero pad memory.
                zero_padder = LLLnode.from_list(
                    ['repeat', zero_pad_i, ['mload', bytez_placeholder], maxlen,
                        ['seq',
                            ['if', ['gt', ['mload', zero_pad_i], maxlen], 'break'],  # stay within allocated bounds
                            ['mstore8', ['add', ['add', 32, bytez_placeholder], ['mload', zero_pad_i]], 0]]],
                    annotation="Zero pad"
                )
            return zero_padder

        sub = Expr(self.stmt.value, self.context).lll_node
        self.context.increment_return_counter()
        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            if not isinstance(self.context.return_type, BaseType):
                raise TypeMismatchException("Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value)
            sub = unwrap_location(sub)
            if not are_units_compatible(sub.typ, self.context.return_type):
                raise TypeMismatchException("Return type units mismatch %r %r" % (sub.typ, self.context.return_type), self.stmt.value)
            elif sub.typ.is_literal and (self.context.return_type.typ == sub.typ or
                    'int' in self.context.return_type.typ and
                    'int' in sub.typ.typ):
                if not SizeLimits.in_bounds(self.context.return_type.typ, sub.value):
                    raise InvalidLiteralException("Number out of range: " + str(sub.value), self.stmt)
                else:
                    return LLLnode.from_list(['seq', ['mstore', 0, sub], self.make_return_stmt(0, 32)], typ=None, pos=getpos(self.stmt))
            elif is_base_type(sub.typ, self.context.return_type.typ) or \
                    (is_base_type(sub.typ, 'int128') and is_base_type(self.context.return_type, 'int256')):
                return LLLnode.from_list(['seq', ['mstore', 0, sub], self.make_return_stmt(0, 32)], typ=None, pos=getpos(self.stmt))
            else:
                raise TypeMismatchException("Unsupported type conversion: %r to %r" % (sub.typ, self.context.return_type), self.stmt.value)
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayType):
            if not isinstance(self.context.return_type, ByteArrayType):
                raise TypeMismatchException("Trying to return base type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value)
            if sub.typ.maxlen > self.context.return_type.maxlen:
                raise TypeMismatchException("Cannot cast from greater max-length %d to shorter max-length %d" %
                                            (sub.typ.maxlen, self.context.return_type.maxlen), self.stmt.value)

            loop_memory_position = self.context.new_placeholder(typ=BaseType('uint256'))  # loop memory has to be allocated first.
            len_placeholder = self.context.new_placeholder(typ=BaseType('uint256'))  # len & bytez placeholder have to be declared after each other at all times.
            bytez_placeholder = self.context.new_placeholder(typ=sub.typ)

            if sub.location in ('storage', 'memory'):
                return LLLnode.from_list([
                    'seq',
                    make_byte_array_copier(
                        LLLnode(bytez_placeholder, location='memory', typ=sub.typ),
                        sub,
                        pos=getpos(self.stmt)
                    ),
                    zero_pad(bytez_placeholder, sub.typ.maxlen),
                    ['mstore', len_placeholder, 32],
                    self.make_return_stmt(len_placeholder, ['ceil32', ['add', ['mload', bytez_placeholder], 64]], loop_memory_position=loop_memory_position)],
                    typ=None, pos=getpos(self.stmt)
                )
            else:
                raise Exception("Invalid location: %s" % sub.location)

        elif isinstance(sub.typ, ListType):
            sub_base_type = re.split(r'\(|\[', str(sub.typ.subtype))[0]
            ret_base_type = re.split(r'\(|\[', str(self.context.return_type.subtype))[0]
            loop_memory_position = self.context.new_placeholder(typ=BaseType('uint256'))
            if sub_base_type != ret_base_type:
                raise TypeMismatchException(
                    "List return type %r does not match specified return type, expecting %r" % (
                        sub_base_type, ret_base_type
                    ),
                    self.stmt
                )
            elif sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list(self.make_return_stmt(sub, get_size_of_type(self.context.return_type) * 32, loop_memory_position=loop_memory_position),
                                            typ=None, pos=getpos(self.stmt))
            else:
                new_sub = LLLnode.from_list(self.context.new_placeholder(self.context.return_type), typ=self.context.return_type, location='memory')
                setter = make_setter(new_sub, sub, 'memory', pos=getpos(self.stmt))
                return LLLnode.from_list(['seq', setter, self.make_return_stmt(new_sub, get_size_of_type(self.context.return_type) * 32, loop_memory_position=loop_memory_position)],
                                            typ=None, pos=getpos(self.stmt))

        # Returning a tuple.
        elif isinstance(sub.typ, TupleType):
            if not isinstance(self.context.return_type, TupleType):
                raise TypeMismatchException("Trying to return tuple type %r, output expecting %r" % (sub.typ, self.context.return_type), self.stmt.value)

            if len(self.context.return_type.members) != len(sub.typ.members):
                raise StructureException("Tuple lengths don't match!", self.stmt)

            # check return type matches, sub type.
            for i, ret_x in enumerate(self.context.return_type.members):
                s_member = sub.typ.members[i]
                sub_type = s_member if isinstance(s_member, NodeType) else s_member.typ
                if type(sub_type) is not type(ret_x):
                    raise StructureException(
                        "Tuple return type does not match annotated return. {} != {}".format(
                            type(sub_type), type(ret_x)
                        ),
                        self.stmt
                    )

            # Is from a call expression.
            if len(sub.args[0].args) > 0 and sub.args[0].args[0].value == 'call':  # self-call to public.
                mem_pos = sub.args[0].args[-1]
                mem_size = get_size_of_type(sub.typ) * 32
                return LLLnode.from_list(['return', mem_pos, mem_size], typ=sub.typ)

            elif (sub.annotation and 'Internal Call' in sub.annotation):
                mem_pos = sub.args[-1].value if sub.value == 'seq_unchecked' else sub.args[0].args[-1]
                mem_size = get_size_of_type(sub.typ) * 32
                # Add zero padder if bytes are present in output.
                zero_padder = ['pass']
                byte_arrays = [(i, x) for i, x in enumerate(sub.typ.members) if isinstance(x, ByteArrayType)]
                if byte_arrays:
                    i, x = byte_arrays[-1]
                    zero_padder = zero_pad(bytez_placeholder=['add', mem_pos, ['mload', mem_pos + i * 32]], maxlen=x.maxlen)
                return LLLnode.from_list(
                    ['seq'] +
                    [sub] +
                    [zero_padder] +
                    [self.make_return_stmt(mem_pos, mem_size)
                ], typ=sub.typ, pos=getpos(self.stmt))

            subs = []
            # Pre-allocate loop_memory_position if required for private function returning.
            loop_memory_position = self.context.new_placeholder(typ=BaseType('uint256')) if self.context.is_private else None
            # Allocate dynamic off set counter, to keep track of the total packed dynamic data size.
            dynamic_offset_counter_placeholder = self.context.new_placeholder(typ=BaseType('uint256'))
            dynamic_offset_counter = LLLnode(
                dynamic_offset_counter_placeholder, typ=None, annotation="dynamic_offset_counter"  # dynamic offset position counter.
            )
            new_sub = LLLnode.from_list(
                self.context.new_placeholder(typ=BaseType('uint256')), typ=self.context.return_type, location='memory', annotation='new_sub'
            )
            keyz = list(range(len(sub.typ.members)))
            dynamic_offset_start = 32 * len(sub.args)  # The static list of args end.
            left_token = LLLnode.from_list('_loc', typ=new_sub.typ, location="memory")

            def get_dynamic_offset_value():
                # Get value of dynamic offset counter.
                return ['mload', dynamic_offset_counter]

            def increment_dynamic_offset(dynamic_spot):
                # Increment dyanmic offset counter in memory.
                return [
                    'mstore', dynamic_offset_counter,
                    ['add',
                        ['add', ['ceil32', ['mload', dynamic_spot]], 32],
                        ['mload', dynamic_offset_counter]]
                ]

            for i, typ in enumerate(keyz):
                arg = sub.args[i]
                variable_offset = LLLnode.from_list(['add', 32 * i, left_token], typ=arg.typ, annotation='variable_offset')
                if isinstance(arg.typ, ByteArrayType):
                    # Store offset pointer value.
                    subs.append(['mstore', variable_offset, get_dynamic_offset_value()])

                    # Store dynamic data, from offset pointer onwards.
                    dynamic_spot = LLLnode.from_list(['add', left_token, get_dynamic_offset_value()], location="memory", typ=arg.typ, annotation='dynamic_spot')
                    subs.append(make_setter(dynamic_spot, arg, location="memory", pos=getpos(self.stmt)))
                    subs.append(increment_dynamic_offset(dynamic_spot))

                elif isinstance(arg.typ, BaseType):
                    subs.append(make_setter(variable_offset, arg, "memory", pos=getpos(self.stmt)))
                else:
                    raise Exception("Can't return type %s as part of tuple", type(arg.typ))

            setter = LLLnode.from_list(
                ['seq',
                    ['mstore', dynamic_offset_counter, dynamic_offset_start],
                    ['with', '_loc', new_sub, ['seq'] + subs]],
                typ=None
            )

            return LLLnode.from_list(
                ['seq',
                    setter,
                    self.make_return_stmt(new_sub, get_dynamic_offset_value(), loop_memory_position)],
                typ=None, pos=getpos(self.stmt)
            )
        else:
            raise TypeMismatchException("Can only return base type!", self.stmt)
コード例 #14
0
ファイル: stmt.py プロジェクト: DadiaoMoe/ophydia
 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))