Repository: vyperlang/vyper

Issue:
Output `methodIdentifiers` in vyper-serve
Hi, I'm one of the authors of Vyper plugin for Remix.
Remix requires method identifies(4 bytes function signatures) of contracts to resolve the called function and correctly parse tx input/output in remix console.

As for Solidity, it's included in the compiler output (https://solidity.readthedocs.io/en/v0.4.25/using-the-compiler.html#output-description) so I want to add it to Vyper compiler, too.

I did a PoC implementation in our fork repository like this. 
https://github.com/LayerXcom/vyper/commit/8d48ebd54096d290109cb7e3964a73128130f80c

For now, I'm waiting #1089 to be merged because it's going to change the format of output.
After that, I'll refine that code and add tests and then create PR :)


Discussion:
Cool, will look at adding it as part of the `combined_json` output.
@jacqueswww 
Thanks! Then we wait it.
@nrryuya @yudetamago I just pushed on #1089, give the branch a go ;) (this should merge today I reckon, just needs a final :+1: ). I will also add a commit for vyper-serve to use the new compile call.
@jacqueswww 
Thanks for merging #1089!
Unfortunately, I found a mistake (which is due to my PoC, sorry).

Post

```python
@public
@constant
def f(_n: uint256) -> uint256:
    return _n
```

to vyper-serve, then the following error has occurres.

```
Listening on http://localhost:8000
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 58639)
Traceback (most recent call last):
  File "/Users/yudetamago/.pyenv/versions/3.6.5/lib/python3.6/socketserver.py", line 639, in process_request_thread
    self.finish_request(request, client_address)
  File "/Users/yudetamago/.pyenv/versions/3.6.5/lib/python3.6/socketserver.py", line 361, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/Users/yudetamago/.pyenv/versions/3.6.5/lib/python3.6/socketserver.py", line 696, in __init__
    self.handle()
  File "/Users/yudetamago/.pyenv/versions/3.6.5/lib/python3.6/http/server.py", line 418, in handle
    self.handle_one_request()
  File "/Users/yudetamago/.pyenv/versions/3.6.5/lib/python3.6/http/server.py", line 406, in handle_one_request
    method()
  File "./bin/vyper-serve", line 64, in do_POST
    response, status_code = self._compile(data)
  File "./bin/vyper-serve", line 89, in _compile
    output_type='dict',
  File "/Users/yudetamago/dev/project/layerx/vyper/venv/lib/python3.6/site-packages/vyper-0.1.0b4-py3.6.egg/vyper/compiler.py", line 110, in compile_codes
    raise exc
  File "/Users/yudetamago/dev/project/layerx/vyper/venv/lib/python3.6/site-packages/vyper-0.1.0b4-py3.6.egg/vyper/compiler.py", line 105, in compile_codes
    out.setdefault(contract_name, {})[output_format] = output_formats_map[output_format](code)
  File "/Users/yudetamago/dev/project/layerx/vyper/venv/lib/python3.6/site-packages/vyper-0.1.0b4-py3.6.egg/vyper/compiler.py", line 92, in <lambda>
    'method_identifiers': lambda code: parser.mk_method_identifiers(code)
  File "/Users/yudetamago/dev/project/layerx/vyper/venv/lib/python3.6/site-packages/vyper-0.1.0b4-py3.6.egg/vyper/parser/parser.py", line 147, in mk_method_identifiers
    o.append(s.get_method_identifier(code, global_ctx._contracts, global_ctx._custom_units))
  File "/Users/yudetamago/dev/project/layerx/vyper/venv/lib/python3.6/site-packages/vyper-0.1.0b4-py3.6.egg/vyper/signatures/function_signature.py", line 178, in get_method_identifier
    sig = FunctionSignature.get_full_sig(self.name, self.args, sigs, custom_units)
  File "/Users/yudetamago/dev/project/layerx/vyper/venv/lib/python3.6/site-packages/vyper-0.1.0b4-py3.6.egg/vyper/signatures/function_signature.py", line 69, in get_full_sig
    return func_name + '(' + ','.join([get_type(arg) for arg in args]) + ')'
TypeError: sequence item 0: expected str instance, NoneType found
----------------------------------------
```

This comes from in this line.
https://github.com/ethereum/vyper/blob/921bb80cf59c9be0067ed20e1a7b6ad0b59598b3/vyper/signatures/function_signature.py#L178
`get_full_sig` requires the list of ast arg, but `self.args` (which is the list of `VariableRecord`) is passed.

Resolving patch:
diff --git a/vyper/parser/parser.py b/vyper/parser/parser.py
--- a/vyper/parser/parser.py
+++ b/vyper/parser/parser.py
@@ -136,7 +136,7 @@ def mk_full_signature(code):
 
 
 def mk_method_identifiers(code):
-    o = []
+    o = {}
     global_ctx = GlobalContext.get_global_context(parse(code))
 
     for code in global_ctx._defs:
@@ -144,9 +144,9 @@ def mk_method_identifiers(code):
         if not sig.private:
             default_sigs = generate_default_arg_sigs(code, global_ctx._contracts, global_ctx._custom_units)
             for s in default_sigs:
-                o.append(s.get_method_identifier(global_ctx._contracts, global_ctx._custom_units))
+                o[s.sig] = hex(s.method_id)
 
-    return dict(o)
+    return o
 
 
 def parse_events(sigs, _events, custom_units=None):
diff --git a/vyper/signatures/function_signature.py b/vyper/signatures/function_signature.py
--- a/vyper/signatures/function_signature.py
+++ b/vyper/signatures/function_signature.py
@@ -174,10 +174,6 @@ def to_abi_dict(self, custom_units_descriptions=None):
 
         return abi_dict
 
-    def get_method_identifier(self, sigs, custom_units):
-        sig = FunctionSignature.get_full_sig(self.name, self.args, sigs, custom_units)
-        return (sig, hex(self.method_id))
-
     @classmethod
     def lookup_sig(cls, sigs, method_name, expr_args, stmt_or_expr, context):
         """ Using a list of args, determine the most accurate signature to use from the given context """


Test patch: