Repository: vyperlang/vyper

Issue:
Allow data part of log opcode to be any length of bytes
### What's your issue about?

![image](https://user-images.githubusercontent.com/6917456/34873213-d85a1b48-f79c-11e7-8b15-51f6f35f17cb.png)

If `log4(p, s, t1, t2, t3, t4)` defines the  log opcode, memory from p to p + s represents the data section of the log[0-4] instruction. t1-t4 are calls for topics (or indexed).  Since the opcode support that to be any length. Currently the un-indexed "data" parameters ( p & s parameters) of a logging operation is limited to 32 bytes in vyper.

The following should work after this fix:

```python
MyLog: __log__({arg1: indexed(bytes <= 3), arg2: bytes <= 64})

@public
def foo():
    log.MyLog('bar', 'stuuuuff')
```
### How can it be fixed?

Add support for it in vyper. Also look at updating pyethereum's `abi.py`  to interpret `bytes[n]` notation on events.

#### Cute Animal Picture

![](https://i.pinimg.com/736x/5d/4e/cc/5d4ecc2145f7153a09b44759319784fe--big-eyes-cool-eyes.jpg)
Limit map key size 
### What's your issue about?
1. In vyper compiler, the key_type of map can only be base type and byte array type, which is inconsistent with the doc(https://github.com/ethereum/vyper/blob/master/docs/types.rst) : "Here _KeyType can be almost any type except for mappings, a contract, or a struct".

2. Assume key type can only be base type and byte array type. I can have the following program:
```
a:num[bytes<=100000]
@public
def __init__():
    self.a["absssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"] = 1
    pass
```
will cause the compiler to throw an error "Can't have a zerovalent argument to an opcode or a pseudo-opcode! seq", which is weird.


### How can it be fixed?

Since the storage is limited, it's better to restrict the size of the key of the map.

#### Cute Animal Picture

![image](https://user-images.githubusercontent.com/5641590/35161380-a92d46f6-fd05-11e7-9148-846a24becb14.png)




Discussion:
Starting with this ;)
@yzhang90 thanks for the report.
Having a look now. 
@DavidKnott @fubuloubu @yzhang90 Ok I have investigated this, there was a fault in the way we did the sha3 accross the key bytearray in the incorrect manner. I have now fixed it that any size can work (any size larger than 32 would've  caused trouble).

Now the question:
Do we want to limit the key size?

Resolving patch:
diff --git a/vyper/parser/parser_utils.py b/vyper/parser/parser_utils.py
--- a/vyper/parser/parser_utils.py
+++ b/vyper/parser/parser_utils.py
@@ -402,18 +402,19 @@ def add_variable_offset(parent, key):
             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))
             subtype = typ.valuetype
-            if len(key.args[0].args) == 3:  # handle bytes literal.
+            if len(key.args[0].args) >= 3:  # handle bytes literal.
                 sub = LLLnode.from_list([
                     'seq',
                     key,
-                    ['sha3', ['add', key.args[0].args[-1], 32], ceil32(key.typ.maxlen)]
+                    ['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], ceil32(key.typ.maxlen)])
+                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)
         if location == 'storage':
+            # import ipdb; ipdb.set_trace()
             return LLLnode.from_list(['add', ['sha3_32', parent], sub],
                                      typ=subtype,
                                      location='storage')
diff --git a/vyper/parser/stmt.py b/vyper/parser/stmt.py
--- a/vyper/parser/stmt.py
+++ b/vyper/parser/stmt.py
@@ -378,6 +378,7 @@ def parse_return(self):
             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 = Expr(self.stmt.value, self.context).lll_node
         self.context.increment_return_counter()
         # Returning a value (most common case)


Test patch:
diff --git a/tests/parser/features/test_bytes_map_keys.py b/tests/parser/features/test_bytes_map_keys.py
--- a/tests/parser/features/test_bytes_map_keys.py
+++ b/tests/parser/features/test_bytes_map_keys.py
@@ -93,3 +93,33 @@ def set(k: bytes <= 35, v: int128):
 
     with pytest.raises(TypeMismatchException):
         get_contract(code)
+
+
+def test_extended_bytes_key_from_storage(get_contract):
+    code = """
+a: int128[bytes<=100000]
+
+@public
+def __init__():
+    self.a["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"] = 1069
+
+@public
+def get_it1() -> int128:
+    key: bytes <= 100000 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    return self.a[key]
+
+@public
+def get_it2() -> int128:
+    return self.a["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
+
+@public
+def get_it3(key: bytes<=100000) -> int128:
+    return self.a[key]
+    """
+
+    c = get_contract(code)
+
+    assert c.get_it2() == 1069
+    assert c.get_it2() == 1069
+    assert c.get_it3(b"a" * 33) == 1069
+    assert c.get_it3(b"test") == 0