Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

External contract call interfaces #1250

Merged
merged 21 commits into from
Feb 26, 2019
Merged
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ea1410d
Add support for builtin interfaces.
jacqueswww Feb 12, 2019
97d534d
Merge branch 'master' into 1214_external_contract_calls
jacqueswww Feb 12, 2019
8f2e5b6
Change existing interfaces in tests.
jacqueswww Feb 13, 2019
777b4db
Only allow address(Bar) definition of persistent contract addresses.
jacqueswww Feb 14, 2019
338c4c9
Fix tests to use address(Foo) style.
jacqueswww Feb 14, 2019
c8ab699
Add docs for external calls using interfaces.
jacqueswww Feb 14, 2019
a81f1f2
Add docs for external calls using interfaces.
jacqueswww Feb 14, 2019
d5ccf54
Ensure signature output type is also compared for interfaces.
jacqueswww Feb 18, 2019
a656e30
Make use of the new interfaces format.
jacqueswww Feb 18, 2019
306b812
Vyper bin will look for .json interfaces now as well.
jacqueswww Feb 18, 2019
34e2670
Add test case for a json interface.
jacqueswww Feb 19, 2019
005fb18
Merge branch 'master' into 1214_external_contract_calls
jacqueswww Feb 19, 2019
15ffde2
Fix for python3.6 ast.
jacqueswww Feb 19, 2019
d82a0d3
Merge master.
jacqueswww Feb 20, 2019
30d8a19
Merge branch 'master' into 1214_external_contract_calls
jacqueswww Feb 20, 2019
006703d
Add strict ContracType(<address>) definition to align with VIP #1251.
jacqueswww Feb 25, 2019
b295c08
Merge branch '1214_external_contract_calls' of github.com:jacqueswww/…
jacqueswww Feb 25, 2019
f3e9934
Merge branch 'master' into 1214_external_contract_calls
jacqueswww Feb 25, 2019
0b7eb36
Merge branch 'master' into 1214_external_contract_calls
jacqueswww Feb 25, 2019
0a45645
Fix docs.
jacqueswww Feb 26, 2019
c2c72ae
Fix tests, for new persistent contract syntax.
jacqueswww Feb 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Merge master.
  • Loading branch information
jacqueswww committed Feb 20, 2019
commit d82a0d386a27ef11ab31e9ecdefba8dfea57a8b0
2 changes: 2 additions & 0 deletions bin/vyper
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ format_options_help = """Format to print, one or more of:
combined_json - All of the above format options combined as single JSON output.
interface - Print Vyper interface of a contract
external_interface - Print Externa Contract of a contract, to be used as outside contract calls.
opcodes - List of opcodes as a string
opcodes_runtime - List of runtime opcodes as a string
"""

parser = argparse.ArgumentParser(
9 changes: 7 additions & 2 deletions docs/installing-vyper.rst
Original file line number Diff line number Diff line change
@@ -173,11 +173,16 @@ Vyper can be downloaded as docker image from dockerhub:

To run the compiler use the `docker run` command:
::
docker run vyper <contract_file.vy>
docker run -v $(pwd):/code vyper /code/<contract_file.vy>

Alternatively you can log into the docker image and execute vyper on the prompt.
::
docker run -v $(pwd):/code/ -it --entrypoint /bin/bash vyper
root@d35252d1fb1b:/code# vyper <contract_file.vy>

The normal paramaters are also supported, for example:
::
docker run vyper -f abi a.vy
docker run -v $(pwd):/code vyper -f abi /code/<contract_file.vy>
[{'name': 'test1', 'outputs': [], 'inputs': [{'type': 'uint256', 'name': 'a'}, {'type': 'bytes', 'name': 'b'}], 'constant': False, 'payable': False, 'type': 'function', 'gas': 441}, {'name': 'test2', 'outputs': [], 'inputs': [{'type': 'uint256', 'name': 'a'}], 'constant': False, 'payable': False, 'type': 'function', 'gas': 316}]


14 changes: 14 additions & 0 deletions tests/compiler/test_opcodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import vyper


def test_opcodes():
code = """
@public
def a() -> bool:
return True
"""

out = vyper.compile_codes({'': code}, ['opcodes_runtime', 'opcodes'])[0]

assert len(out['opcodes']) > len(out['opcodes_runtime'])
assert out['opcodes_runtime'] in out['opcodes']
3 changes: 3 additions & 0 deletions vyper/compile_lll.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import functools

from vyper.parser.parser import LLLnode
from .opcodes import opcodes
from vyper.utils import MemoryPositions
@@ -52,6 +54,7 @@ def __init__(self, sstr, pos=None):


def apply_line_numbers(func):
@functools.wraps(func)
def apply_line_no_wrapper(*args, **kwargs):
code = args[0]
ret = func(*args, **kwargs)
47 changes: 40 additions & 7 deletions vyper/compiler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from vyper.opcodes import opcodes
from vyper.parser import parser
from vyper import compile_lll
from vyper import optimizer
from collections import OrderedDict
from collections import OrderedDict, deque
from vyper.signatures.interface import (
extract_interface_str,
extract_external_interface,
@@ -24,7 +25,7 @@ def find_nested_opcode(asm_list, key):
return True
else:
sublists = [sub for sub in asm_list if isinstance(sub, list)]
return any([find_nested_opcode(x, key) for x in sublists])
return any(find_nested_opcode(x, key) for x in sublists)

if find_nested_opcode(asm, 'DEBUG'):
print('Please note this code contains DEBUG opcode.')
@@ -54,11 +55,18 @@ def mk_full_signature(code, *args, **kwargs):
abi = parser.mk_full_signature(parser.parse_to_ast(code), *args, **kwargs)
# Add gas estimates for each function to ABI
gas_estimates = gas_estimate(code, *args, **kwargs)
for idx, func in enumerate(abi):
func_name = func.get('name', '').split('(')[0]
# Skip __init__, has no estimate
for func in abi:
try:
func_signature = func['name']
except KeyError:
# constructor and fallback functions don't have a name
continue

func_name, _, _ = func_signature.partition('(')
# This check ensures we skip __init__ since it has no estimate
if func_name in gas_estimates:
abi[idx]['gas'] = gas_estimates[func_name]
# TODO: mutation
func['gas'] = gas_estimates[func_name]
return abi


@@ -98,6 +106,27 @@ def get_source_map(code, contract_name, interface_codes=None):
return out


def get_opcodes(code, contract_name, bytecodes_runtime=False, interface_codes=None):
bytecode = __compile(
code,
bytecode_runtime=bytecodes_runtime,
interface_codes=interface_codes
).hex().upper()
bytecode = deque(bytecode[i:i + 2] for i in range(0, len(bytecode), 2))
opcode_map = dict((v[0], k) for k, v in opcodes.items())
opcode_str = ""

while bytecode:
op = int(bytecode.popleft(), 16)
opcode_str += opcode_map[op] + " "
if "PUSH" not in opcode_map[op]:
continue
push_len = int(opcode_map[op][4:])
opcode_str += "0x" + "".join(bytecode.popleft() for i in range(push_len)) + " "

return opcode_str[:-1]


output_formats_map = {
'abi': lambda code, contract_name, interface_codes: mk_full_signature(code, interface_codes=interface_codes),
'bytecode': lambda code, contract_name, interface_codes: '0x' + __compile(code, interface_codes=interface_codes).hex(),
@@ -108,10 +137,14 @@ def get_source_map(code, contract_name, interface_codes=None):
'method_identifiers': lambda code, contract_name, interface_codes: parser.mk_method_identifiers(code, interface_codes=interface_codes),
'interface': lambda code, contract_name, interface_codes: extract_interface_str(code, contract_name, interface_codes=interface_codes),
'external_interface': lambda code, contract_name, interface_codes: extract_external_interface(code, contract_name, interface_codes=interface_codes),
'opcodes': lambda code, contract_name, interface_codes: get_opcodes(code, contract_name, interface_codes=interface_codes),
'opcodes_runtime': lambda code, contract_name, interface_codes: get_opcodes(code, contract_name, bytecodes_runtime=True, interface_codes=interface_codes),
}


def compile_codes(codes, output_formats=['bytecode'], output_type='list', exc_handler=None, interface_codes=None):
def compile_codes(codes, output_formats=None, output_type='list', exc_handler=None, interface_codes=None):
if output_formats is None:
output_formats = ('bytecode',)

out = OrderedDict()
for contract_name, code in codes.items():
2 changes: 2 additions & 0 deletions vyper/functions/signature.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ast
import functools

from vyper.parser.parser_utils import (
get_original_if_0_prefixed,
@@ -94,6 +95,7 @@ def process_arg(index, arg, expected_arg_typelist, function_name, context):

def signature(*argz, **kwargz):
def decorator(f):
@functools.wraps(f)
def g(element, context):
function_name = element.func.id
if len(element.args) > len(argz):
64 changes: 64 additions & 0 deletions vyper/opcodes.py
Original file line number Diff line number Diff line change
@@ -54,6 +54,70 @@
'MSIZE': [0x59, 0, 1, 2],
'GAS': [0x5a, 0, 1, 2],
'JUMPDEST': [0x5b, 0, 0, 1],
'PUSH1': [0x60, 0, 1, 3],
'PUSH2': [0x61, 0, 1, 3],
'PUSH3': [0x62, 0, 1, 3],
'PUSH4': [0x63, 0, 1, 3],
'PUSH5': [0x64, 0, 1, 3],
'PUSH6': [0x65, 0, 1, 3],
'PUSH7': [0x66, 0, 1, 3],
'PUSH8': [0x67, 0, 1, 3],
'PUSH9': [0x68, 0, 1, 3],
'PUSH10': [0x69, 0, 1, 3],
'PUSH11': [0x6a, 0, 1, 3],
'PUSH12': [0x6b, 0, 1, 3],
'PUSH13': [0x6c, 0, 1, 3],
'PUSH14': [0x6d, 0, 1, 3],
'PUSH15': [0x6e, 0, 1, 3],
'PUSH16': [0x6f, 0, 1, 3],
'PUSH17': [0x70, 0, 1, 3],
'PUSH18': [0x71, 0, 1, 3],
'PUSH19': [0x72, 0, 1, 3],
'PUSH20': [0x73, 0, 1, 3],
'PUSH21': [0x74, 0, 1, 3],
'PUSH22': [0x75, 0, 1, 3],
'PUSH23': [0x76, 0, 1, 3],
'PUSH24': [0x77, 0, 1, 3],
'PUSH25': [0x78, 0, 1, 3],
'PUSH26': [0x79, 0, 1, 3],
'PUSH27': [0x7a, 0, 1, 3],
'PUSH28': [0x7b, 0, 1, 3],
'PUSH29': [0x7c, 0, 1, 3],
'PUSH30': [0x7d, 0, 1, 3],
'PUSH31': [0x7e, 0, 1, 3],
'PUSH32': [0x7f, 0, 1, 3],
'DUP1': [0x80, 1, 2, 3],
'DUP2': [0x81, 1, 2, 3],
'DUP3': [0x82, 1, 2, 3],
'DUP4': [0x83, 1, 2, 3],
'DUP5': [0x84, 1, 2, 3],
'DUP6': [0x85, 1, 2, 3],
'DUP7': [0x86, 1, 2, 3],
'DUP8': [0x87, 1, 2, 3],
'DUP9': [0x88, 1, 2, 3],
'DUP10': [0x89, 1, 2, 3],
'DUP11': [0x8a, 1, 2, 3],
'DUP12': [0x8b, 1, 2, 3],
'DUP13': [0x8c, 1, 2, 3],
'DUP14': [0x8d, 1, 2, 3],
'DUP15': [0x8e, 1, 2, 3],
'DUP16': [0x8f, 1, 2, 3],
'SWAP1': [0x90, 2, 2, 3],
'SWAP2': [0x91, 2, 2, 3],
'SWAP3': [0x92, 2, 2, 3],
'SWAP4': [0x93, 2, 2, 3],
'SWAP5': [0x94, 2, 2, 3],
'SWAP6': [0x95, 2, 2, 3],
'SWAP7': [0x96, 2, 2, 3],
'SWAP8': [0x97, 2, 2, 3],
'SWAP9': [0x98, 2, 2, 3],
'SWAP10': [0x99, 2, 2, 3],
'SWAP11': [0x9a, 2, 2, 3],
'SWAP12': [0x9b, 2, 2, 3],
'SWAP13': [0x9c, 2, 2, 3],
'SWAP14': [0x9d, 2, 2, 3],
'SWAP15': [0x9e, 2, 2, 3],
'SWAP16': [0x9f, 2, 2, 3],
'LOG0': [0xa0, 2, 0, 375],
'LOG1': [0xa1, 3, 0, 750],
'LOG2': [0xa2, 4, 0, 1125],