Esempio n. 1
0
 def from_declaration(cls, code):
     name = code.target.id
     pos = 0
     # 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 hasattr(
                     typ,
                     'left') and typ.left.id == 'bytes' and typ.comparators[
                         0].n > 32 and is_indexed:
                 raise VariableDeclarationException(
                     "Indexed arguments are limited to 32 bytes")
             if topics_count > 4:
                 raise VariableDeclarationException(
                     "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):
                 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)
             args.append(VariableRecord(arg, pos, parsed_type, False))
             if isinstance(parsed_type, ByteArrayType):
                 pos += ceil32(typ.comparators[0].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)
     ]) + ')'
     event_id = bytes_to_int(sha3(bytes(sig, 'utf-8')))
     return cls(name, args, indexed_list, event_id, sig)
Esempio n. 2
0
def pack_arguments(signature, args, context):
    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
    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 + 32 + i * 32, typ=typ), arg,
                    'memory'))
        elif isinstance(typ, ByteArrayType):
            setters.append(['mstore', placeholder + 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),
                    [
                        'set', '_poz',
                        ['add', 32, ['add', '_poz',
                                     get_length(arg_copy)]]
                    ]
                ]
            ])
            needpos = True
        else:
            raise TypeMismatchException("Cannot pack argument of type %r" %
                                        typ)
    if needpos:
        return LLLnode.from_list(['with', '_poz', len(args) * 32, ['seq'] + setters + [placeholder + 28]],
                                 typ=placeholder_typ, location='memory'), \
            placeholder_typ.maxlen - 28
    else:
        return LLLnode.from_list(['seq'] + setters + [placeholder + 28], typ=placeholder_typ, location='memory'), \
            placeholder_typ.maxlen - 28
Esempio n. 3
0
 def parse_return(self):
     from .parser import (parse_expr, make_setter)
     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(['return', 0, 0],
                                  typ=None,
                                  pos=getpos(self.stmt))
     if not self.stmt.value:
         raise TypeMismatchException("Expecting to return a value",
                                     self.stmt)
     sub = parse_expr(self.stmt.value, self.context)
     # 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 is_base_type(sub.typ, self.context.return_type.typ) or \
                 (is_base_type(sub.typ, 'num') and is_base_type(self.context.return_type, 'signed256')):
             return LLLnode.from_list(
                 ['seq', ['mstore', 0, sub], ['return', 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)
         # Returning something already in memory
         if sub.location == 'memory':
             return LLLnode.from_list([
                 'with', '_loc', sub,
                 [
                     'seq', ['mstore', ['sub', '_loc', 32], 32],
                     [
                         'return', ['sub', '_loc', 32],
                         ['ceil32', ['add', ['mload', '_loc'], 64]]
                     ]
                 ]
             ],
                                      typ=None,
                                      pos=getpos(self.stmt))
         # Copying from storage
         elif sub.location == 'storage':
             # Instantiate a byte array at some index
             fake_byte_array = LLLnode(self.context.get_next_mem() + 32,
                                       typ=sub.typ,
                                       location='memory',
                                       pos=getpos(self.stmt))
             o = [
                 'seq',
                 # Copy the data to this byte array
                 make_byte_array_copier(fake_byte_array, sub),
                 # Store the number 32 before it for ABI formatting purposes
                 ['mstore', self.context.get_next_mem(), 32],
                 # Return it
                 [
                     'return',
                     self.context.get_next_mem(),
                     [
                         'add',
                         [
                             'ceil32',
                             ['mload',
                              self.context.get_next_mem() + 32]
                         ], 64
                     ]
                 ]
             ]
             return LLLnode.from_list(o, typ=None, pos=getpos(self.stmt))
         else:
             raise Exception("Invalid location: %s" % sub.location)
     # Returning a list
     elif isinstance(sub.typ, ListType):
         if sub.location == "memory" and sub.value != "multi":
             return LLLnode.from_list([
                 'return', sub,
                 get_size_of_type(self.context.return_type) * 32
             ],
                                      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')
             return LLLnode.from_list([
                 'seq', setter,
                 [
                     'return', new_sub,
                     get_size_of_type(self.context.return_type) * 32
                 ]
             ],
                                      typ=None,
                                      pos=getpos(self.stmt))
     else:
         raise TypeMismatchException("Can only return base type!",
                                     self.stmt)