Skip to content

Commit

Permalink
change notify implementation, following preview3 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
meevee98 committed Jul 30, 2020
1 parent 0d000cc commit 00110e6
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 25 deletions.
10 changes: 5 additions & 5 deletions boa3/model/builtin/builtin.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from typing import Dict, List, Optional, Tuple, Union

from boa3.model.builtin.builtincallable import IBuiltinCallable
from boa3.model.builtin.classmethod.appendmethod import AppendMethod
from boa3.model.builtin.classmethod.clearmethod import ClearMethod
from boa3.model.builtin.classmethod.extendmethod import ExtendMethod
from boa3.model.builtin.classmethod.mapkeysmethod import MapKeysMethod
from boa3.model.builtin.classmethod.mapvaluesmethod import MapValuesMethod
from boa3.model.builtin.classmethod.reversemethod import ReverseMethod
from boa3.model.builtin.decorator.builtindecorator import IBuiltinDecorator
from boa3.model.builtin.decorator.eventdecorator import EventDecorator
from boa3.model.builtin.decorator.metadatadecorator import MetadataDecorator
from boa3.model.builtin.decorator.publicdecorator import PublicDecorator
Expand All @@ -15,20 +15,20 @@
from boa3.model.builtin.method.bytearraymethod import ByteArrayMethod
from boa3.model.builtin.method.lenmethod import LenMethod
from boa3.model.builtin.neometadatatype import MetadataTypeSingleton as NeoMetadataType
from boa3.model.callable import Callable
from boa3.model.identifiedsymbol import IdentifiedSymbol
from boa3.model.method import Method
from boa3.model.type.itype import IType


class Builtin:
@classmethod
def get_symbol(cls, symbol_id: str) -> Optional[Method]:
def get_symbol(cls, symbol_id: str) -> Optional[Callable]:
for name, method in vars(cls).items():
if isinstance(method, IBuiltinDecorator) and method.identifier == symbol_id:
if isinstance(method, IBuiltinCallable) and method.identifier == symbol_id:
return method

@classmethod
def get_by_self(cls, symbol_id: str, self_type: IType) -> Optional[Method]:
def get_by_self(cls, symbol_id: str, self_type: IType) -> Optional[Callable]:
for name, method in vars(cls).items():
if (isinstance(method, IBuiltinMethod)
and method.identifier == symbol_id
Expand Down
23 changes: 23 additions & 0 deletions boa3/model/builtin/builtincallable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from abc import ABC
from typing import Dict, List, Tuple

from boa3.model.callable import Callable
from boa3.model.identifiedsymbol import IdentifiedSymbol
from boa3.model.type.itype import IType
from boa3.model.variable import Variable
from boa3.neo.vm.opcode.Opcode import Opcode


class IBuiltinCallable(Callable, IdentifiedSymbol, ABC):
def __init__(self, identifier: str, args: Dict[str, Variable] = None, return_type: IType = None):
super().__init__(args, return_type)
self._identifier = identifier

@property
def opcode(self) -> List[Tuple[Opcode, bytes]]:
"""
Gets the opcode for the method.
:return: the opcode and its data if exists. None otherwise.
"""
return []
7 changes: 3 additions & 4 deletions boa3/model/builtin/decorator/builtindecorator.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
from abc import ABC, abstractmethod
from typing import Dict

from boa3.model.builtin.builtincallable import IBuiltinCallable
from boa3.model.expression import IExpression
from boa3.model.identifiedsymbol import IdentifiedSymbol
from boa3.model.method import Method
from boa3.model.type.itype import IType
from boa3.model.variable import Variable


class IBuiltinDecorator(Method, IdentifiedSymbol, ABC):
class IBuiltinDecorator(IBuiltinCallable, Method, ABC):
def __init__(self, identifier: str, args: Dict[str, Variable] = None, return_type: IType = None):
super().__init__(args, return_type)
self._identifier = identifier
super().__init__(identifier, args, return_type)

@abstractmethod
def validate_parameters(self, *params: IExpression) -> bool:
Expand Down
28 changes: 28 additions & 0 deletions boa3/model/builtin/interop/interopevent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from abc import ABC
from typing import Dict, List, Tuple

from boa3.model.builtin.method.builtinevent import IBuiltinEvent
from boa3.model.variable import Variable
from boa3.neo.vm.opcode.Opcode import Opcode


class InteropEvent(IBuiltinEvent, ABC):

def __init__(self, identifier: str, sys_call: str, args: Dict[str, Variable] = None):
self._sys_call: str = sys_call
super().__init__(identifier, args)

@property
def interop_method_hash(self) -> bytes:
return self._method_hash(self._sys_call)

def _method_hash(self, method_name: str) -> bytes:
from boa3.constants import SIZE_OF_INT32
from boa3.neo import cryptography
from boa3.neo.vm.type.String import String

return cryptography.sha256(String(method_name).to_bytes())[:SIZE_OF_INT32]

@property
def opcode(self) -> List[Tuple[Opcode, bytes]]:
return [(Opcode.SYSCALL, self.interop_method_hash)]
6 changes: 3 additions & 3 deletions boa3/model/builtin/interop/runtime/notifymethod.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from typing import Dict

from boa3.model.builtin.interop.interopmethod import InteropMethod
from boa3.model.builtin.interop.interopevent import InteropEvent
from boa3.model.variable import Variable


class NotifyMethod(InteropMethod):
class NotifyMethod(InteropEvent):

def __init__(self):
from boa3.model.type.type import Type
identifier = 'notify'
syscall = 'System.Runtime.Notify'
args: Dict[str, Variable] = {'state': Variable(Type.any)}
super().__init__(identifier, syscall, args, Type.none)
super().__init__(identifier, syscall, args)
12 changes: 12 additions & 0 deletions boa3/model/builtin/method/builtinevent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from abc import ABC
from typing import Dict

from boa3.model.builtin.builtincallable import IBuiltinCallable
from boa3.model.event import Event
from boa3.model.variable import Variable


class IBuiltinEvent(IBuiltinCallable, Event, ABC):
def __init__(self, identifier: str, args: Dict[str, Variable] = None):
from boa3.model.type.type import Type
super().__init__(identifier, args, Type.none)
17 changes: 4 additions & 13 deletions boa3/model/builtin/method/builtinmethod.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, Optional

from boa3.model.builtin.decorator.builtindecorator import IBuiltinDecorator
from boa3.model.builtin.builtincallable import IBuiltinCallable
from boa3.model.method import Method
from boa3.model.type.itype import IType
from boa3.model.variable import Variable
from boa3.neo.vm.opcode.Opcode import Opcode


class IBuiltinMethod(IBuiltinDecorator, ABC):
class IBuiltinMethod(IBuiltinCallable, Method, ABC):
def __init__(self, identifier: str, args: Dict[str, Variable] = None, return_type: IType = None):
super().__init__(identifier, args, return_type)

@property
def opcode(self) -> List[Tuple[Opcode, bytes]]:
"""
Gets the opcode for the method.
:return: the opcode and its data if exists. None otherwise.
"""
return []

@property
def is_supported(self) -> bool:
"""
Expand Down
20 changes: 20 additions & 0 deletions boa3_test/tests/test_file_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,26 @@ def test_generate_nefdbgnfo_file_with_event(self):
self.assertIn(param_id, actual_event.args)
self.assertEqual(param_type, actual_event.args[param_id].type.abi_type)

def test_generate_manifest_file_with_notify_event(self):
path = '%s/boa3_test/example/interop_test/NotifySequence.py' % self.dirname
expected_manifest_output = path.replace('.py', '.manifest.json')
output, manifest = self.compile_and_save(path)

self.assertTrue(os.path.exists(expected_manifest_output))
self.assertIn('abi', manifest)
abi = manifest['abi']

self.assertIn('events', abi)
self.assertGreater(len(abi['events']), 0)

notify_event = next(abi_event for abi_event in abi['events']
if 'name' in abi_event and abi_event['name'] == 'notify')
self.assertIsNotNone(notify_event, "notify event is not listed in the contract's abi")
self.assertIn('parameters', notify_event)
self.assertEqual(1, len(notify_event['parameters']))
self.assertIn('type', notify_event['parameters'][0])
self.assertEqual(AbiType.Any, notify_event['parameters'][0]['type'])

def test_generate_without_main(self):
path = '%s/boa3_test/example/generation_test/GenerationWithoutMain.py' % self.dirname
expected_manifest_output = path.replace('.py', '.manifest.json')
Expand Down
30 changes: 30 additions & 0 deletions boa3_test/tests/test_interop.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ def test_check_witness_mismatched_type(self):
self.assertCompilerLogs(MismatchedTypes, path)

def test_notify_str(self):
event_name = String('notify').to_bytes()
string = String('str').to_bytes()
expected_output = (
Opcode.PUSHDATA1
+ Integer(len(string)).to_byte_array(min_length=1)
+ string
+ Opcode.PUSH1
+ Opcode.PACK
+ Opcode.PUSHDATA1
+ Integer(len(event_name)).to_byte_array(min_length=1)
+ event_name
+ Opcode.SYSCALL
+ Interop.Notify.interop_method_hash
+ Opcode.PUSHNULL
Expand All @@ -62,8 +68,14 @@ def test_notify_str(self):
self.assertEqual(expected_output, output)

def test_notify_int(self):
event_name = String('notify').to_bytes()
expected_output = (
Opcode.PUSH15
+ Opcode.PUSH1
+ Opcode.PACK
+ Opcode.PUSHDATA1
+ Integer(len(event_name)).to_byte_array(min_length=1)
+ event_name
+ Opcode.SYSCALL
+ Interop.Notify.interop_method_hash
+ Opcode.PUSHNULL
Expand All @@ -75,8 +87,14 @@ def test_notify_int(self):
self.assertEqual(expected_output, output)

def test_notify_bool(self):
event_name = String('notify').to_bytes()
expected_output = (
Opcode.PUSH1
+ Opcode.PUSH1
+ Opcode.PACK
+ Opcode.PUSHDATA1
+ Integer(len(event_name)).to_byte_array(min_length=1)
+ event_name
+ Opcode.SYSCALL
+ Interop.Notify.interop_method_hash
+ Opcode.PUSHNULL
Expand All @@ -88,8 +106,14 @@ def test_notify_bool(self):
self.assertEqual(expected_output, output)

def test_notify_none(self):
event_name = String('notify').to_bytes()
expected_output = (
Opcode.PUSHNULL
+ Opcode.PUSH1
+ Opcode.PACK
+ Opcode.PUSHDATA1
+ Integer(len(event_name)).to_byte_array(min_length=1)
+ event_name
+ Opcode.SYSCALL
+ Interop.Notify.interop_method_hash
+ Opcode.PUSHNULL
Expand All @@ -101,13 +125,19 @@ def test_notify_none(self):
self.assertEqual(expected_output, output)

def test_notify_sequence(self):
event_name = String('notify').to_bytes()
expected_output = (
Opcode.PUSH7
+ Opcode.PUSH5
+ Opcode.PUSH3
+ Opcode.PUSH2
+ Opcode.PUSH4
+ Opcode.PACK
+ Opcode.PUSH1
+ Opcode.PACK
+ Opcode.PUSHDATA1
+ Integer(len(event_name)).to_byte_array(min_length=1)
+ event_name
+ Opcode.SYSCALL
+ Interop.Notify.interop_method_hash
+ Opcode.PUSHNULL
Expand Down

0 comments on commit 00110e6

Please sign in to comment.