Skip to content

Commit

Permalink
CU-86drpncy1 - Add new methods on storage to get/put primitive values…
Browse files Browse the repository at this point in the history
… without the need of TypeHelper
  • Loading branch information
Mirella de Medeiros committed Apr 2, 2024
1 parent d15ecaf commit 2a45b5b
Show file tree
Hide file tree
Showing 73 changed files with 1,045 additions and 340 deletions.
263 changes: 258 additions & 5 deletions boa3/builtin/interop/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,21 @@
'StorageContext',
'StorageMap',
'get',
'get_int',
'get_bool',
'get_str',
'get_uint160',
'get_uint256',
'get_ecpoint',
'get_context',
'get_read_only_context',
'put',
'put_int',
'put_bool',
'put_str',
'put_uint160',
'put_uint256',
'put_ecpoint',
'delete',
'find',
]
Expand All @@ -14,6 +26,7 @@
from boa3.builtin.interop.storage.findoptions import FindOptions
from boa3.builtin.interop.storage.storagecontext import StorageContext
from boa3.builtin.interop.storage.storagemap import StorageMap
from boa3.builtin.type import UInt160, UInt256, ECPoint


def get_context() -> StorageContext:
Expand All @@ -35,7 +48,7 @@ def get(key: bytes, context: StorageContext = get_context()) -> bytes:
>>> put(b'unit', 'test')
... get(b'unit')
'test'
b'test'
>>> get(b'fake_key')
''
Expand All @@ -50,6 +63,138 @@ def get(key: bytes, context: StorageContext = get_context()) -> bytes:
pass


def get_int(key: bytes, context: StorageContext = get_context()) -> int:
"""
Gets a value as integer from the persistent store based on the given key.
It's equivalent to boa3.builtin.type.helper.to_int(get(key, context))
>>> put_int(b'unit', 5)
... get_int(b'unit')
5
>>> get_int(b'fake_key')
''
:param key: value identifier in the store
:type key: bytes
:param context: storage context to be used
:type context: StorageContext
:return: the value corresponding to given key for current storage context
:rtype: int
"""
pass


def get_bool(key: bytes, context: StorageContext = get_context()) -> bool:
"""
Gets a value as boolean from the persistent store based on the given key.
It's equivalent to boa3.builtin.type.helper.to_bool(get(key, context))
>>> put_bool(b'unit', True)
... get_bool(b'unit')
True
>>> get_bool(b'fake_key')
''
:param key: value identifier in the store
:type key: bytes
:param context: storage context to be used
:type context: StorageContext
:return: the value corresponding to given key for current storage context
:rtype: bool
"""
pass


def get_str(key: bytes, context: StorageContext = get_context()) -> str:
"""
Gets a value as string from the persistent store based on the given key.
It's equivalent to boa3.builtin.type.helper.to_str(get(key, context))
>>> put_str(b'unit', 'test')
... get_str(b'unit')
'test'
>>> get_str(b'fake_key')
''
:param key: value identifier in the store
:type key: bytes
:param context: storage context to be used
:type context: StorageContext
:return: the value corresponding to given key for current storage context
:rtype: str
"""
pass


def get_uint160(key: bytes, context: StorageContext = get_context()) -> UInt160:
"""
Gets a value as UInt160 from the persistent store based on the given key.
It's equivalent UInt160(get(key, context))
>>> put_uint160(b'unit', UInt160(b'0123456789ABCDEFGHIJ'))
... get_uint160(b'unit')
UInt160(0x4a49484746454443424139383736353433323130)
>>> get_uint160(b'fake_key')
''
:param key: value identifier in the store
:type key: bytes
:param context: storage context to be used
:type context: StorageContext
:return: the value corresponding to given key for current storage context
:rtype: UInt160
"""
pass


def get_uint256(key: bytes, context: StorageContext = get_context()) -> UInt256:
"""
Gets a value as UInt256 from the persistent store based on the given key.
It's equivalent UInt256(get(key, context))
>>> put_uint256(b'unit', UInt256(b'0123456789ABCDEFGHIJKLMNOPQRSTUV'))
... get_uint256(b'unit')
UInt256(0x565554535251504f4e4d4c4b4a49484746454443424139383736353433323130)
>>> get_uint160(b'fake_key')
''
:param key: value identifier in the store
:type key: bytes
:param context: storage context to be used
:type context: StorageContext
:return: the value corresponding to given key for current storage context
:rtype: UInt256
"""
pass


def get_ecpoint(key: bytes, context: StorageContext = get_context()) -> ECPoint:
"""
Gets a value as ECPoint from the persistent store based on the given key.
It's equivalent ECPoint(get(key, context))
>>> put_ecpoint(b'unit', ECPoint(b'0123456789ABCDEFGHIJKLMNOPQRSTUVW'))
... get_ecpoint(b'unit')
ECPoint(0x57565554535251504f4e4d4c4b4a49484746454443424139383736353433323130)
>>> get_ecpoint(b'fake_key')
''
:param key: value identifier in the store
:type key: bytes
:param context: storage context to be used
:type context: StorageContext
:return: the value corresponding to given key for current storage context
:rtype: ECPoint
"""
pass


def get_read_only_context() -> StorageContext:
"""
Gets current read only storage context.
Expand All @@ -63,17 +208,125 @@ def get_read_only_context() -> StorageContext:
pass


def put(key: bytes, value: int | bytes | str, context: StorageContext = get_context()):
def put(key: bytes, value: bytes, context: StorageContext = get_context()):
"""
Inserts a given value in the key-value format into the persistent storage.
Inserts a given bytes value in the key-value format into the persistent storage.
>>> put(b'unit', 'test')
>>> put(b'unit', b'test')
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: bytes
:param context: storage context to be used
:type context: StorageContext
"""
pass


def put_int(key: bytes, value: int, context: StorageContext = get_context()):
"""
Inserts a given integer value in the key-value format into the persistent storage.
It's equivalent to put(key, boa3.builtin.type.helper.to_int(value), context)
>>> put_int(b'unit', 5)
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: int
:param context: storage context to be used
:type context: StorageContext
"""
pass


def put_bool(key: bytes, value: bool, context: StorageContext = get_context()):
"""
Inserts a given boolean value in the key-value format into the persistent storage.
It's equivalent to put(key, boa3.builtin.type.helper.to_bool(value), context)
>>> put_bool(b'unit', True)
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: bool
:param context: storage context to be used
:type context: StorageContext
"""
pass


def put_str(key: bytes, value: str, context: StorageContext = get_context()):
"""
Inserts a given str value in the key-value format into the persistent storage.
It's equivalent to put(key, boa3.builtin.type.helper.to_str(value), context)
>>> put_str(b'unit', 'test')
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: str
:param context: storage context to be used
:type context: StorageContext
"""
pass


def put_uint160(key: bytes, value: UInt160, context: StorageContext = get_context()):
"""
Inserts a given UInt160 value in the key-value format into the persistent storage.
It's equivalent to put(key, value, context) since UInt160 is a subclass of bytes
>>> put_uint160(b'unit', UInt160(b'0123456789ABCDEFGHIJ'))
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: UInt160
:param context: storage context to be used
:type context: StorageContext
"""
pass


def put_uint256(key: bytes, value: UInt256, context: StorageContext = get_context()):
"""
Inserts a given UInt256 value in the key-value format into the persistent storage.
It's equivalent to put(key, value, context) since UInt256 is a subclass of bytes
>>> put_uint256(b'unit', UInt256(b'0123456789ABCDEFGHIJKLMNOPQRSTUV'))
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: UInt256
:param context: storage context to be used
:type context: StorageContext
"""
pass


def put_ecpoint(key: bytes, value: ECPoint, context: StorageContext = get_context()):
"""
Inserts a given ECPoint value in the key-value format into the persistent storage.
It's equivalent to put(key, value, context) since ECPoint is a subclass of bytes
>>> put_ecpoint(b'unit', ECPoint(b'0123456789ABCDEFGHIJKLMNOPQRSTUVW'))
None
:param key: the identifier in the store for the new value
:type key: bytes
:param value: value to be stored
:type value: int or str or bytes
:type value: ECPoint
:param context: storage context to be used
:type context: StorageContext
"""
Expand Down
5 changes: 4 additions & 1 deletion boa3/builtin/type/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class UInt160(bytes):
"""
Represents a 160-bit unsigned integer.
"""
zero: UInt160

def __init__(self, arg: bytes | int = 0):
super().__init__()
Expand All @@ -50,6 +51,7 @@ class UInt256(bytes):
"""
Represents a 256-bit unsigned integer.
"""
zero: UInt256

def __init__(self, arg: bytes | int = 0):
super().__init__()
Expand All @@ -60,12 +62,13 @@ class ECPoint(bytes):
"""
Represents a coordinate pair for elliptic curve cryptography (ECC) structures.
"""
zero: ECPoint

def __init__(self, arg: bytes):
super().__init__()
pass

def to_script_hash(self) -> bytes:
def to_script_hash(self) -> UInt160:
"""
Converts a data to a script hash.
Expand Down
7 changes: 5 additions & 2 deletions boa3/internal/compiler/codegenerator/codegenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,14 @@ def stack_size(self) -> int:
return len(self._stack)

def _stack_append(self, value_type: IType):
self._stack_states.append(value_type, self.last_code)
self._stack_states.append(self.last_code, value_type)

def _stack_pop(self, index: int = -1) -> IType:
return self._stack_states.pop(self.last_code, index)

def _stack_reverse(self, start: int = 0, end: int = None, *, rotate: bool = False) -> IType:
return self._stack_states.reverse(self.last_code, start, end, rotate=rotate)

@property
def last_code_start_address(self) -> int:
"""
Expand Down Expand Up @@ -2408,7 +2411,7 @@ def swap_reverse_stack_items(self, no_items: int = 0, rotate: bool = False):
if opcode is Opcode.REVERSEN and no_items > 0:
self._stack_pop()
if no_items > 0:
self._stack.reverse(-no_items, rotate=rotate)
self._stack_reverse(-no_items, rotate=rotate)

def convert_init_user_class(self, class_type: ClassType):
if isinstance(class_type, UserClass):
Expand Down
18 changes: 17 additions & 1 deletion boa3/internal/compiler/codegenerator/engine/stackmemento.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def restore_state(self, code_address):
if latest_stack is not None:
self._current_stack = latest_stack

def append(self, value: IType, code: VMCode):
def append(self, code: VMCode, value: IType):
states = self.stack_map
index = VMCodeMapping.instance().get_start_address(code)
if index in states:
Expand Down Expand Up @@ -90,6 +90,22 @@ def pop(self, code: VMCode, index: int = -1):
if len(stack) > 0:
return stack.pop(index)

def reverse(self, code: VMCode, start: int = 0, end: int = None, *, rotate: bool = False):
states = self.stack_map
stack_index = VMCodeMapping.instance().get_start_address(code)
if stack_index in states:
stack = states[stack_index]
else:
if self._current_stack is not None:
stack = self._current_stack.copy()
else:
stack = NeoStack()

self._stacks.append((code, stack))
self._current_stack = stack

return stack.reverse(start, end, rotate=rotate)


class NeoStack(IStack):
def __init__(self):
Expand Down
Loading

0 comments on commit 2a45b5b

Please sign in to comment.