From 8e679cda8c40f444f134d1dd3a649e3d5e84f580 Mon Sep 17 00:00:00 2001 From: Mirella de Medeiros Date: Thu, 9 May 2024 12:54:10 -0300 Subject: [PATCH] #86drpne63 - Add new methods on storage to get/put arrays, maps and objects without the need of stdlib convertion --- boa3/builtin/interop/storage/__init__.py | 211 +++++++++++++++++- .../compiler/codegenerator/codegenerator.py | 7 +- .../internal/model/builtin/interop/interop.py | 18 ++ .../model/builtin/interop/storage/__init__.py | 9 + .../builtin/interop/storage/get/__init__.py | 3 + .../storage/get/storagegetdictmethod.py | 22 ++ .../storage/get/storagegetlistmethod.py | 22 ++ .../storage/get/storagegetobjectmethod.py | 22 ++ .../interop/storage/getcheck/__init__.py | 3 + .../storage/getcheck/storagegetdictmethod.py | 22 ++ .../storage/getcheck/storagegetlistmethod.py | 22 ++ .../getcheck/storagegetobjectmethod.py | 22 ++ .../builtin/interop/storage/put/__init__.py | 3 + .../storage/put/storageputdictmethod.py | 17 ++ .../storage/put/storageputlistmethod.py | 17 ++ .../storage/put/storageputobjectmethod.py | 17 ++ boa3/internal/model/sc/__init__.py | 9 + boa3/sc/storage/__init__.py | 202 ++++++++++++++++- boa3_test/examples/nep11_non_divisible.py | 17 +- .../IntToBytesAsParameter.py | 3 +- .../iterator/IteratorImplicitTyping.py | 3 +- .../iterator/IteratorValueAccess.py | 3 +- .../runtime/ExecutingScriptHashOnDeploy.py | 5 +- .../while_test/WhileWithInteropCondition.py | 6 +- 24 files changed, 656 insertions(+), 29 deletions(-) create mode 100644 boa3/internal/model/builtin/interop/storage/get/storagegetdictmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/get/storagegetlistmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/get/storagegetobjectmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/getcheck/storagegetdictmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/getcheck/storagegetlistmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/getcheck/storagegetobjectmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/put/storageputdictmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/put/storageputlistmethod.py create mode 100644 boa3/internal/model/builtin/interop/storage/put/storageputobjectmethod.py diff --git a/boa3/builtin/interop/storage/__init__.py b/boa3/builtin/interop/storage/__init__.py index b9751748a..97fb4f3d0 100644 --- a/boa3/builtin/interop/storage/__init__.py +++ b/boa3/builtin/interop/storage/__init__.py @@ -6,6 +6,9 @@ 'get_int', 'get_bool', 'get_str', + 'get_list', + 'get_dict', + 'get_object', 'get_uint160', 'get_uint256', 'get_ecpoint', @@ -13,6 +16,9 @@ 'try_get_int', 'try_get_bool', 'try_get_str', + 'try_get_list', + 'try_get_dict', + 'try_get_object', 'try_get_uint160', 'try_get_uint256', 'try_get_ecpoint', @@ -22,6 +28,9 @@ 'put_int', 'put_bool', 'put_str', + 'put_list', + 'put_dict', + 'put_object', 'put_uint160', 'put_uint256', 'put_ecpoint', @@ -29,6 +38,8 @@ 'find', ] +from typing import Any + from deprecation import deprecated from boa3.builtin.interop.iterator import Iterator @@ -57,7 +68,7 @@ def get(key: bytes, context: StorageContext = get_context()) -> bytes: """ Gets a value from the persistent store based on the given key. - >>> put(b'unit', 'test') + >>> put(b'unit', b'test') ... get(b'unit') b'test' @@ -79,7 +90,7 @@ def try_get(key: bytes, context: StorageContext = get_context()) -> tuple[bytes, """ Gets a value from the persistent store based on the given key and returns whether the value is stored. - >>> put(b'unit', 'test') + >>> put(b'unit', b'test') ... try_get(b'unit') (b'test', True) @@ -231,6 +242,144 @@ def try_get_str(key: bytes, context: StorageContext = get_context()) -> tuple[st pass +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def get_list(key: bytes, context: StorageContext = get_context()) -> list: + """ + Gets a value as list from the persistent store based on the given key. + It's equivalent to boa3.builtin.nativecontract.stdlib.StdLib.deserialize(get(key, context)) + + >>> put_list(b'unit', [1, 2, '3']) + ... get_list(b'unit') + [1, 2, '3'] + + >>> get_list(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: list + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def try_get_list(key: bytes, context: StorageContext = get_context()) -> tuple[list, bool]: + """ + Gets a value as list from the persistent store based on the given key and returns whether the value is stored. + + >>> put_list(b'unit', [1, 2, '3']) + ... try_get_list(b'unit') + ([1, 2, '3'], True) + + >>> get_list(b'fake_key') + ([], False) + + :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 and whether it was actually stored + :rtype: tuple[list, bool] + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def get_dict(key: bytes, context: StorageContext = get_context()) -> dict: + """ + Gets a value as dict from the persistent store based on the given key. + It's equivalent to boa3.builtin.nativecontract.stdlib.StdLib.deserialize(get(key, context)) + + >>> put_dict(b'unit', {'example': 1, 'other_example': 2}) + ... get_dict(b'unit') + {'example': 1, 'other_example': 2} + + >>> get_dict(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: dict + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def try_get_dict(key: bytes, context: StorageContext = get_context()) -> tuple[dict, bool]: + """ + Gets a value as dict from the persistent store based on the given key and returns whether the value is stored. + + >>> put_dict(b'unit', {'example': 1, 'other_example': 2}) + ... get_dict(b'unit') + ({'example': 1, 'other_example': 2}, True) + + >>> get_dict(b'fake_key') + ({}, False) + + :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 and whether it was actually stored + :rtype: tuple[dict, bool] + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def get_object(key: bytes, context: StorageContext = get_context()) -> Any: + """ + Gets a value as object from the persistent store based on the given key. + It's equivalent to boa3.builtin.nativecontract.stdlib.StdLib.deserialize(get(key, context)) + Returns an empty struct if not found. + + >>> example = SomeClass() + >>> put_object(b'unit', example) + ... get_object(b'unit') + SomeClass + + >>> get_object(b'fake_key') + object + + :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: Any + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def try_get_object(key: bytes, context: StorageContext = get_context()) -> tuple[Any, bool]: + """ + Gets a value as dict from the persistent store based on the given key and returns whether the value is stored. + + >>> example = SomeClass() + >>> put_object(b'unit', example) + ... try_get_object(b'unit') + (SomeClass, True) + + >>> get_object(b'fake_key') + (object, False) + + :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 and whether it was actually stored + :rtype: tuple[Any, bool] + """ + pass + + @deprecated(details='This module is deprecated. Use boa3.sc.storage instead') def get_uint160(key: bytes, context: StorageContext = get_context()) -> UInt160: """ @@ -455,6 +604,64 @@ def put_str(key: bytes, value: str, context: StorageContext = get_context()): pass +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def put_list(key: bytes, value: list, context: StorageContext = get_context()): + """ + Inserts a given list value in the key-value format into the persistent storage. + It's equivalent to put(key, boa3.builtin.nativecontract.stdlib.serialize(value), context) + + >>> put_list(b'unit', [1, 2, '3']) + None + + :param key: the identifier in the store for the new value + :type key: bytes + :param value: value to be stored + :type value: list + :param context: storage context to be used + :type context: StorageContext + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def put_dict(key: bytes, value: dict, context: StorageContext = get_context()): + """ + Inserts a given dict value in the key-value format into the persistent storage. + It's equivalent to put(key, boa3.builtin.nativecontract.stdlib.serialize(value), context) + + >>> put_dict(b'unit', {'example': 1, 'other_example': 2}) + None + + :param key: the identifier in the store for the new value + :type key: bytes + :param value: value to be stored + :type value: dict + :param context: storage context to be used + :type context: StorageContext + """ + pass + + +@deprecated(details='This module is deprecated. Use boa3.sc.storage instead') +def put_object(key: bytes, value: object, context: StorageContext = get_context()): + """ + Inserts a given object value in the key-value format into the persistent storage. + It's equivalent to put(key, boa3.builtin.nativecontract.stdlib.serialize(value), context) + + >>> example = SomeClass() + >>> put_object(b'unit', example) + None + + :param key: the identifier in the store for the new value + :type key: bytes + :param value: value to be stored + :type value: dict + :param context: storage context to be used + :type context: StorageContext + """ + pass + + @deprecated(details='This module is deprecated. Use boa3.sc.storage instead') def put_uint160(key: bytes, value: UInt160, context: StorageContext = get_context()): """ diff --git a/boa3/internal/compiler/codegenerator/codegenerator.py b/boa3/internal/compiler/codegenerator/codegenerator.py index b2311b6ca..5666aaff5 100644 --- a/boa3/internal/compiler/codegenerator/codegenerator.py +++ b/boa3/internal/compiler/codegenerator/codegenerator.py @@ -1202,19 +1202,20 @@ def convert_new_map(self, map_type: IType): self.__insert1(OpcodeInfo.NEWMAP) self._stack_append(map_type) - def convert_new_empty_array(self, length: int, array_type: IType): + def convert_new_empty_array(self, length: int, array_type: IType, *, as_struct: bool = False): """ Converts the creation of a new empty array :param length: the size of the new array :param array_type: the Neo Boa type of the array + :param as_struct: convert as struct instead of array """ if length <= 0: - self.__insert1(OpcodeInfo.NEWARRAY0) + self.__insert1(OpcodeInfo.NEWARRAY0 if not as_struct else OpcodeInfo.NEWSTRUCT0) else: self.convert_literal(length) self._stack_pop() - self.__insert1(OpcodeInfo.NEWARRAY) + self.__insert1(OpcodeInfo.NEWARRAY if not as_struct else OpcodeInfo.NEWSTRUCT) self._stack_append(array_type) def convert_new_array(self, length: int, array_type: IType = Type.list): diff --git a/boa3/internal/model/builtin/interop/interop.py b/boa3/internal/model/builtin/interop/interop.py index bd777647d..7d2414351 100644 --- a/boa3/internal/model/builtin/interop/interop.py +++ b/boa3/internal/model/builtin/interop/interop.py @@ -196,6 +196,9 @@ def interop_events(cls) -> list[Event]: StorageGetInt = StorageGetIntMethod() StorageGetBool = StorageGetBoolMethod() StorageGetStr = StorageGetStrMethod() + StorageGetList = StorageGetListMethod() + StorageGetDict = StorageGetDictMethod() + StorageGetObject = StorageGetObjectMethod() StorageGetUInt160 = StorageGetUInt160Method() StorageGetUInt256 = StorageGetUInt256Method() StorageGetECPoint = StorageGetECPointMethod() @@ -203,6 +206,9 @@ def interop_events(cls) -> list[Event]: StorageGetCheckInt = StorageTryGetIntMethod() StorageGetCheckBool = StorageTryGetBoolMethod() StorageGetCheckStr = StorageTryGetStrMethod() + StorageGetCheckList = StorageTryGetListMethod() + StorageGetCheckDict = StorageTryGetDictMethod() + StorageGetCheckObject = StorageTryGetObjectMethod() StorageGetCheckUInt160 = StorageTryGetUInt160Method() StorageGetCheckUInt256 = StorageTryGetUInt256Method() StorageGetCheckECPoint = StorageTryGetECPointMethod() @@ -210,6 +216,9 @@ def interop_events(cls) -> list[Event]: StoragePutInt = StoragePutIntMethod() StoragePutBool = StoragePutBoolMethod() StoragePutStr = StoragePutStrMethod() + StoragePutList = StoragePutListMethod() + StoragePutDict = StoragePutDictMethod() + StoragePutObject = StoragePutObjectMethod() StoragePutUInt160 = StoragePutUInt160Method() StoragePutUInt256 = StoragePutUInt256Method() StoragePutECPoint = StoragePutECPointMethod() @@ -457,6 +466,9 @@ def interop_events(cls) -> list[Event]: StorageGetInt, StorageGetBool, StorageGetStr, + StorageGetList, + StorageGetDict, + StorageGetObject, StorageGetUInt160, StorageGetUInt256, StorageGetECPoint, @@ -464,6 +476,9 @@ def interop_events(cls) -> list[Event]: StorageGetCheckInt, StorageGetCheckBool, StorageGetCheckStr, + StorageGetCheckList, + StorageGetCheckDict, + StorageGetCheckObject, StorageGetCheckUInt160, StorageGetCheckUInt256, StorageGetCheckECPoint, @@ -473,6 +488,9 @@ def interop_events(cls) -> list[Event]: StoragePutInt, StoragePutBool, StoragePutStr, + StoragePutList, + StoragePutDict, + StoragePutObject, StoragePutUInt160, StoragePutUInt256, StoragePutECPoint, diff --git a/boa3/internal/model/builtin/interop/storage/__init__.py b/boa3/internal/model/builtin/interop/storage/__init__.py index 7daf04893..8409981f0 100644 --- a/boa3/internal/model/builtin/interop/storage/__init__.py +++ b/boa3/internal/model/builtin/interop/storage/__init__.py @@ -6,23 +6,32 @@ 'StorageGetReadOnlyContextMethod', 'StorageGetBoolMethod', 'StorageGetBytesMethod', + 'StorageGetDictMethod', 'StorageGetECPointMethod', 'StorageGetIntMethod', + 'StorageGetListMethod', + 'StorageGetObjectMethod', 'StorageGetStrMethod', 'StorageGetUInt160Method', 'StorageGetUInt256Method', 'StorageMapType', 'StoragePutBoolMethod', 'StoragePutBytesMethod', + 'StoragePutDictMethod', 'StoragePutECPointMethod', 'StoragePutIntMethod', + 'StoragePutListMethod', + 'StoragePutObjectMethod', 'StoragePutStrMethod', 'StoragePutUInt160Method', 'StoragePutUInt256Method', 'StorageTryGetBoolMethod', 'StorageTryGetBytesMethod', + 'StorageTryGetDictMethod', 'StorageTryGetECPointMethod', 'StorageTryGetIntMethod', + 'StorageTryGetListMethod', + 'StorageTryGetObjectMethod', 'StorageTryGetStrMethod', 'StorageTryGetUInt160Method', 'StorageTryGetUInt256Method', diff --git a/boa3/internal/model/builtin/interop/storage/get/__init__.py b/boa3/internal/model/builtin/interop/storage/get/__init__.py index d93948138..151a95119 100644 --- a/boa3/internal/model/builtin/interop/storage/get/__init__.py +++ b/boa3/internal/model/builtin/interop/storage/get/__init__.py @@ -1,7 +1,10 @@ from boa3.internal.model.builtin.interop.storage.get.storagegetboolmethod import StorageGetBoolMethod from boa3.internal.model.builtin.interop.storage.get.storagegetbytesmethod import StorageGetBytesMethod +from boa3.internal.model.builtin.interop.storage.get.storagegetdictmethod import StorageGetDictMethod from boa3.internal.model.builtin.interop.storage.get.storagegetecpointmethod import StorageGetECPointMethod from boa3.internal.model.builtin.interop.storage.get.storagegetintmethod import StorageGetIntMethod +from boa3.internal.model.builtin.interop.storage.get.storagegetlistmethod import StorageGetListMethod +from boa3.internal.model.builtin.interop.storage.get.storagegetobjectmethod import StorageGetObjectMethod from boa3.internal.model.builtin.interop.storage.get.storagegetstrmethod import StorageGetStrMethod from boa3.internal.model.builtin.interop.storage.get.storagegetuint160method import StorageGetUInt160Method from boa3.internal.model.builtin.interop.storage.get.storagegetuint256method import StorageGetUInt256Method diff --git a/boa3/internal/model/builtin/interop/storage/get/storagegetdictmethod.py b/boa3/internal/model/builtin/interop/storage/get/storagegetdictmethod.py new file mode 100644 index 000000000..dd08eff60 --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/get/storagegetdictmethod.py @@ -0,0 +1,22 @@ +from boa3.internal.model.builtin.interop.storage.get.istoragegetmethod import IStorageGetMethod + + +class StorageGetDictMethod(IStorageGetMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'get_dict' + value_type = Type.dict + + super().__init__(identifier, value_type=value_type) + + def generate_default_value_opcodes(self, code_generator): + from boa3.internal.model.type.type import Type + # default_value = {} + code_generator.convert_new_map(Type.dict) + + def generate_deserialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Deserialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/get/storagegetlistmethod.py b/boa3/internal/model/builtin/interop/storage/get/storagegetlistmethod.py new file mode 100644 index 000000000..c9a3a596c --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/get/storagegetlistmethod.py @@ -0,0 +1,22 @@ +from boa3.internal.model.builtin.interop.storage.get.istoragegetmethod import IStorageGetMethod + + +class StorageGetListMethod(IStorageGetMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'get_list' + value_type = Type.list + + super().__init__(identifier, value_type=value_type) + + def generate_default_value_opcodes(self, code_generator): + from boa3.internal.model.type.type import Type + # default_value = [] + code_generator.convert_new_empty_array(0, Type.list) + + def generate_deserialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Deserialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/get/storagegetobjectmethod.py b/boa3/internal/model/builtin/interop/storage/get/storagegetobjectmethod.py new file mode 100644 index 000000000..06d84b9ea --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/get/storagegetobjectmethod.py @@ -0,0 +1,22 @@ +from boa3.internal.model.builtin.interop.storage.get.istoragegetmethod import IStorageGetMethod + + +class StorageGetObjectMethod(IStorageGetMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'get_object' + value_type = Type.any + + super().__init__(identifier, value_type=value_type) + + def generate_default_value_opcodes(self, code_generator): + from boa3.internal.model.type.type import Type + # default_value = object() + code_generator.convert_new_empty_array(0, Type.list, as_struct=True) + + def generate_deserialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Deserialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/getcheck/__init__.py b/boa3/internal/model/builtin/interop/storage/getcheck/__init__.py index a641bfdd4..c14a8c015 100644 --- a/boa3/internal/model/builtin/interop/storage/getcheck/__init__.py +++ b/boa3/internal/model/builtin/interop/storage/getcheck/__init__.py @@ -1,7 +1,10 @@ from boa3.internal.model.builtin.interop.storage.getcheck.storagegetboolmethod import StorageTryGetBoolMethod from boa3.internal.model.builtin.interop.storage.getcheck.storagegetbytesmethod import StorageTryGetBytesMethod +from boa3.internal.model.builtin.interop.storage.getcheck.storagegetdictmethod import StorageTryGetDictMethod from boa3.internal.model.builtin.interop.storage.getcheck.storagegetecpointmethod import StorageTryGetECPointMethod from boa3.internal.model.builtin.interop.storage.getcheck.storagegetintmethod import StorageTryGetIntMethod +from boa3.internal.model.builtin.interop.storage.getcheck.storagegetlistmethod import StorageTryGetListMethod +from boa3.internal.model.builtin.interop.storage.getcheck.storagegetobjectmethod import StorageTryGetObjectMethod from boa3.internal.model.builtin.interop.storage.getcheck.storagegetstrmethod import StorageTryGetStrMethod from boa3.internal.model.builtin.interop.storage.getcheck.storagegetuint160method import StorageTryGetUInt160Method from boa3.internal.model.builtin.interop.storage.getcheck.storagegetuint256method import StorageTryGetUInt256Method diff --git a/boa3/internal/model/builtin/interop/storage/getcheck/storagegetdictmethod.py b/boa3/internal/model/builtin/interop/storage/getcheck/storagegetdictmethod.py new file mode 100644 index 000000000..c42d51b53 --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/getcheck/storagegetdictmethod.py @@ -0,0 +1,22 @@ +from boa3.internal.model.builtin.interop.storage.getcheck.istoragetrygetmethod import IStorageTryGetMethod + + +class StorageTryGetDictMethod(IStorageTryGetMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'try_get_dict' + value_type = Type.dict + + super().__init__(identifier, value_type=value_type) + + def generate_default_value_opcodes(self, code_generator): + from boa3.internal.model.type.type import Type + # default_value = {} + code_generator.convert_new_map(Type.dict) + + def generate_deserialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Deserialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/getcheck/storagegetlistmethod.py b/boa3/internal/model/builtin/interop/storage/getcheck/storagegetlistmethod.py new file mode 100644 index 000000000..45fc16d3d --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/getcheck/storagegetlistmethod.py @@ -0,0 +1,22 @@ +from boa3.internal.model.builtin.interop.storage.getcheck.istoragetrygetmethod import IStorageTryGetMethod + + +class StorageTryGetListMethod(IStorageTryGetMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'try_get_list' + value_type = Type.list + + super().__init__(identifier, value_type=value_type) + + def generate_default_value_opcodes(self, code_generator): + from boa3.internal.model.type.type import Type + # default_value = [] + code_generator.convert_new_empty_array(0, Type.list) + + def generate_deserialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Deserialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/getcheck/storagegetobjectmethod.py b/boa3/internal/model/builtin/interop/storage/getcheck/storagegetobjectmethod.py new file mode 100644 index 000000000..e0dd83f79 --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/getcheck/storagegetobjectmethod.py @@ -0,0 +1,22 @@ +from boa3.internal.model.builtin.interop.storage.getcheck.istoragetrygetmethod import IStorageTryGetMethod + + +class StorageTryGetObjectMethod(IStorageTryGetMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'try_get_object' + value_type = Type.any + + super().__init__(identifier, value_type=value_type) + + def generate_default_value_opcodes(self, code_generator): + from boa3.internal.model.type.type import Type + # default_value = object() + code_generator.convert_new_empty_array(0, Type.list, as_struct=True) + + def generate_deserialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Deserialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/put/__init__.py b/boa3/internal/model/builtin/interop/storage/put/__init__.py index fa6bb1ac3..c667c6af1 100644 --- a/boa3/internal/model/builtin/interop/storage/put/__init__.py +++ b/boa3/internal/model/builtin/interop/storage/put/__init__.py @@ -1,7 +1,10 @@ from boa3.internal.model.builtin.interop.storage.put.storageputboolmethod import StoragePutBoolMethod from boa3.internal.model.builtin.interop.storage.put.storageputbytesmethod import StoragePutBytesMethod +from boa3.internal.model.builtin.interop.storage.put.storageputdictmethod import StoragePutDictMethod from boa3.internal.model.builtin.interop.storage.put.storageputecpointmethod import StoragePutECPointMethod from boa3.internal.model.builtin.interop.storage.put.storageputintmethod import StoragePutIntMethod +from boa3.internal.model.builtin.interop.storage.put.storageputlistmethod import StoragePutListMethod +from boa3.internal.model.builtin.interop.storage.put.storageputobjectmethod import StoragePutObjectMethod from boa3.internal.model.builtin.interop.storage.put.storageputstrmethod import StoragePutStrMethod from boa3.internal.model.builtin.interop.storage.put.storageputuint160method import StoragePutUInt160Method from boa3.internal.model.builtin.interop.storage.put.storageputuint256method import StoragePutUInt256Method diff --git a/boa3/internal/model/builtin/interop/storage/put/storageputdictmethod.py b/boa3/internal/model/builtin/interop/storage/put/storageputdictmethod.py new file mode 100644 index 000000000..1f27b9235 --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/put/storageputdictmethod.py @@ -0,0 +1,17 @@ +from boa3.internal.model.builtin.interop.storage.put.istorageputmethod import IStoragePutMethod + + +class StoragePutDictMethod(IStoragePutMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'put_dict' + value_type = Type.dict + + super().__init__(identifier, value_type=value_type) + + def generate_serialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Serialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/put/storageputlistmethod.py b/boa3/internal/model/builtin/interop/storage/put/storageputlistmethod.py new file mode 100644 index 000000000..a12307273 --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/put/storageputlistmethod.py @@ -0,0 +1,17 @@ +from boa3.internal.model.builtin.interop.storage.put.istorageputmethod import IStoragePutMethod + + +class StoragePutListMethod(IStoragePutMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'put_list' + value_type = Type.list + + super().__init__(identifier, value_type=value_type) + + def generate_serialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Serialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/builtin/interop/storage/put/storageputobjectmethod.py b/boa3/internal/model/builtin/interop/storage/put/storageputobjectmethod.py new file mode 100644 index 000000000..47c474dca --- /dev/null +++ b/boa3/internal/model/builtin/interop/storage/put/storageputobjectmethod.py @@ -0,0 +1,17 @@ +from boa3.internal.model.builtin.interop.storage.put.istorageputmethod import IStoragePutMethod + + +class StoragePutObjectMethod(IStoragePutMethod): + def __init__(self): + from boa3.internal.model.type.type import Type + + identifier = 'put_object' + value_type = Type.any + + super().__init__(identifier, value_type=value_type) + + def generate_serialize_value_opcodes(self, code_generator): + from boa3.internal.model.builtin.interop.interop import Interop + + converter = Interop.Serialize + code_generator.convert_builtin_method_call(converter, is_internal=True) diff --git a/boa3/internal/model/sc/__init__.py b/boa3/internal/model/sc/__init__.py index 051a41afe..92de8f2c4 100644 --- a/boa3/internal/model/sc/__init__.py +++ b/boa3/internal/model/sc/__init__.py @@ -43,6 +43,9 @@ def package_symbols(cls, package: str = None) -> Package | None: Interop.StorageGetInt, Interop.StorageGetBool, Interop.StorageGetStr, + Interop.StorageGetList, + Interop.StorageGetDict, + Interop.StorageGetObject, Interop.StorageGetUInt160, Interop.StorageGetUInt256, Interop.StorageGetECPoint, @@ -51,6 +54,9 @@ def package_symbols(cls, package: str = None) -> Package | None: Interop.StorageGetCheckInt, Interop.StorageGetCheckBool, Interop.StorageGetCheckStr, + Interop.StorageGetCheckList, + Interop.StorageGetCheckDict, + Interop.StorageGetCheckObject, Interop.StorageGetCheckUInt160, Interop.StorageGetCheckUInt256, Interop.StorageGetCheckECPoint, @@ -59,6 +65,9 @@ def package_symbols(cls, package: str = None) -> Package | None: Interop.StoragePutInt, Interop.StoragePutBool, Interop.StoragePutStr, + Interop.StoragePutList, + Interop.StoragePutDict, + Interop.StoragePutObject, Interop.StoragePutUInt160, Interop.StoragePutUInt256, Interop.StoragePutECPoint, diff --git a/boa3/sc/storage/__init__.py b/boa3/sc/storage/__init__.py index 2418f8457..9f5847b88 100644 --- a/boa3/sc/storage/__init__.py +++ b/boa3/sc/storage/__init__.py @@ -5,6 +5,9 @@ 'get_int', 'get_bool', 'get_str', + 'get_list', + 'get_dict', + 'get_object', 'get_uint160', 'get_uint256', 'get_ecpoint', @@ -12,6 +15,9 @@ 'try_get_int', 'try_get_bool', 'try_get_str', + 'try_get_list', + 'try_get_dict', + 'try_get_object', 'try_get_uint160', 'try_get_uint256', 'try_get_ecpoint', @@ -21,6 +27,9 @@ 'put_int', 'put_bool', 'put_str', + 'put_list', + 'put_dict', + 'put_object', 'put_uint160', 'put_uint256', 'put_ecpoint', @@ -28,6 +37,8 @@ 'find', ] +from typing import Any + from boa3.builtin.interop.iterator import Iterator from boa3.builtin.type import UInt160, UInt256, ECPoint from boa3.sc.storage.storagecontext import StorageContext @@ -52,7 +63,7 @@ def get(key: bytes, context: StorageContext = get_context()) -> bytes: """ Gets a value from the persistent store based on the given key. - >>> put(b'unit', 'test') + >>> put(b'unit', b'test') ... get(b'unit') b'test' @@ -73,7 +84,7 @@ def try_get(key: bytes, context: StorageContext = get_context()) -> tuple[bytes, """ Gets a value from the persistent store based on the given key and returns whether the value is stored. - >>> put(b'unit', 'test') + >>> put(b'unit', b'test') ... try_get(b'unit') (b'test', True) @@ -219,6 +230,138 @@ def try_get_str(key: bytes, context: StorageContext = get_context()) -> tuple[st pass +def get_list(key: bytes, context: StorageContext = get_context()) -> list: + """ + Gets a value as list from the persistent store based on the given key. + It's equivalent to boa3.builtin.nativecontract.stdlib.StdLib.deserialize(get(key, context)) + + >>> put_list(b'unit', [1, 2, '3']) + ... get_list(b'unit') + [1, 2, '3'] + + >>> get_list(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: list + """ + pass + + +def try_get_list(key: bytes, context: StorageContext = get_context()) -> tuple[list, bool]: + """ + Gets a value as list from the persistent store based on the given key and returns whether the value is stored. + + >>> put_list(b'unit', [1, 2, '3']) + ... try_get_list(b'unit') + ([1, 2, '3'], True) + + >>> get_list(b'fake_key') + ([], False) + + :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 and whether it was actually stored + :rtype: tuple[list, bool] + """ + pass + + +def get_dict(key: bytes, context: StorageContext = get_context()) -> dict: + """ + Gets a value as dict from the persistent store based on the given key. + It's equivalent to boa3.builtin.nativecontract.stdlib.StdLib.deserialize(get(key, context)) + + >>> put_dict(b'unit', {'example': 1, 'other_example': 2}) + ... get_dict(b'unit') + {'example': 1, 'other_example': 2} + + >>> get_dict(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: dict + """ + pass + + +def try_get_dict(key: bytes, context: StorageContext = get_context()) -> tuple[dict, bool]: + """ + Gets a value as dict from the persistent store based on the given key and returns whether the value is stored. + + >>> put_dict(b'unit', {'example': 1, 'other_example': 2}) + ... get_dict(b'unit') + ({'example': 1, 'other_example': 2}, True) + + >>> get_dict(b'fake_key') + ({}, False) + + :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 and whether it was actually stored + :rtype: tuple[dict, bool] + """ + pass + + +def get_object(key: bytes, context: StorageContext = get_context()) -> Any: + """ + Gets a value as object from the persistent store based on the given key. + It's equivalent to boa3.builtin.nativecontract.stdlib.StdLib.deserialize(get(key, context)) + Returns an empty struct if not found. + + >>> example = SomeClass() + >>> put_object(b'unit', example) + ... get_object(b'unit') + SomeClass + + >>> get_object(b'fake_key') + object + + :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: Any + """ + pass + + +def try_get_object(key: bytes, context: StorageContext = get_context()) -> tuple[Any, bool]: + """ + Gets a value as dict from the persistent store based on the given key and returns whether the value is stored. + + >>> example = SomeClass() + >>> put_object(b'unit', example) + ... try_get_object(b'unit') + (SomeClass, True) + + >>> get_object(b'fake_key') + (object, False) + + :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 and whether it was actually stored + :rtype: tuple[Any, bool] + """ + 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. @@ -432,6 +575,61 @@ def put_str(key: bytes, value: str, context: StorageContext = get_context()): pass +def put_list(key: bytes, value: list, context: StorageContext = get_context()): + """ + Inserts a given list value in the key-value format into the persistent storage. + It's equivalent to put(key, boa3.builtin.nativecontract.stdlib.serialize(value), context) + + >>> put_list(b'unit', [1, 2, '3']) + None + + :param key: the identifier in the store for the new value + :type key: bytes + :param value: value to be stored + :type value: list + :param context: storage context to be used + :type context: StorageContext + """ + pass + + +def put_dict(key: bytes, value: dict, context: StorageContext = get_context()): + """ + Inserts a given dict value in the key-value format into the persistent storage. + It's equivalent to put(key, boa3.builtin.nativecontract.stdlib.serialize(value), context) + + >>> put_dict(b'unit', {'example': 1, 'other_example': 2}) + None + + :param key: the identifier in the store for the new value + :type key: bytes + :param value: value to be stored + :type value: dict + :param context: storage context to be used + :type context: StorageContext + """ + pass + + +def put_object(key: bytes, value: object, context: StorageContext = get_context()): + """ + Inserts a given object value in the key-value format into the persistent storage. + It's equivalent to put(key, boa3.builtin.nativecontract.stdlib.serialize(value), context) + + >>> example = SomeClass() + >>> put_object(b'unit', example) + None + + :param key: the identifier in the store for the new value + :type key: bytes + :param value: value to be stored + :type value: dict + :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. diff --git a/boa3_test/examples/nep11_non_divisible.py b/boa3_test/examples/nep11_non_divisible.py index fd08e47b0..b808b0b54 100644 --- a/boa3_test/examples/nep11_non_divisible.py +++ b/boa3_test/examples/nep11_non_divisible.py @@ -12,7 +12,6 @@ from boa3.builtin.interop.iterator import Iterator from boa3.builtin.interop.json import json_deserialize from boa3.builtin.interop.runtime import check_witness, get_network, script_container -from boa3.builtin.interop.stdlib import deserialize, serialize from boa3.builtin.type import UInt160, helper as type_helper from boa3.sc import storage from boa3.sc.types import FindOptions @@ -380,8 +379,7 @@ def internal_deploy(owner: UInt160): auth: list[UInt160] = [] auth.append(owner) - serialized = serialize(auth) - storage.put(AUTH_ADDRESSES, serialized) + storage.put_list(AUTH_ADDRESSES, auth) @public(name='onNEP11Payment') @@ -510,8 +508,7 @@ def getAuthorizedAddress() -> list[UInt160]: :return: whether the transaction signature is correct :raise AssertionError: raised if witness is not verified. """ - serialized = storage.get(AUTH_ADDRESSES, storage.get_read_only_context()) - auth = cast(list[UInt160], deserialize(serialized)) + auth = cast(list[UInt160], storage.get_list(AUTH_ADDRESSES, storage.get_read_only_context())) return auth @@ -536,8 +533,7 @@ def setAuthorizedAddress(address: UInt160, authorized: bool): expect(verified, '`account` is not allowed for setAuthorizedAddress') expect(validateAddress(address), "Not a valid address") expect(isinstance(authorized, bool), "authorized has to be of type bool") - serialized = storage.get(AUTH_ADDRESSES, storage.get_read_only_context()) - auth = cast(list[UInt160], deserialize(serialized)) + auth = cast(list[UInt160], storage.get_list(AUTH_ADDRESSES, storage.get_read_only_context())) if authorized: found = False @@ -549,11 +545,11 @@ def setAuthorizedAddress(address: UInt160, authorized: bool): if not found: auth.append(address) - storage.put(AUTH_ADDRESSES, serialize(auth)) + storage.put_list(AUTH_ADDRESSES, auth) on_auth(address, 0, True) else: auth.remove(address) - storage.put(AUTH_ADDRESSES, serialize(auth)) + storage.put_list(AUTH_ADDRESSES, auth) on_auth(address, 0, False) @@ -601,8 +597,7 @@ def verify() -> bool: :return: whether the transaction signature is correct """ - serialized = storage.get(AUTH_ADDRESSES, storage.get_read_only_context()) - auth = cast(list[UInt160], deserialize(serialized)) + auth = cast(list[UInt160], storage.get_list(AUTH_ADDRESSES, storage.get_read_only_context())) tx = script_container for addr in auth: if check_witness(addr): diff --git a/boa3_test/test_sc/built_in_methods_test/IntToBytesAsParameter.py b/boa3_test/test_sc/built_in_methods_test/IntToBytesAsParameter.py index 7420a4c5e..6b815eef1 100644 --- a/boa3_test/test_sc/built_in_methods_test/IntToBytesAsParameter.py +++ b/boa3_test/test_sc/built_in_methods_test/IntToBytesAsParameter.py @@ -1,5 +1,4 @@ from boa3.builtin.compile_time import public -from boa3.builtin.interop.stdlib import serialize from boa3.builtin.type.helper import to_bytes from boa3.sc import storage @@ -20,4 +19,4 @@ def __init__(self, current_supply: int): def set_value(token_id: bytes, example_class: Example): - storage.put(b'00' + token_id, serialize(example_class)) + storage.put_object(b'00' + token_id, example_class) diff --git a/boa3_test/test_sc/interop_test/iterator/IteratorImplicitTyping.py b/boa3_test/test_sc/interop_test/iterator/IteratorImplicitTyping.py index 6c423374b..7b509e38e 100644 --- a/boa3_test/test_sc/interop_test/iterator/IteratorImplicitTyping.py +++ b/boa3_test/test_sc/interop_test/iterator/IteratorImplicitTyping.py @@ -7,8 +7,7 @@ @public def store(prefix: bytes, value: Any): - serialized_value = StdLib.serialize(value) - storage.put(prefix, serialized_value) + storage.put_object(prefix, value) @public diff --git a/boa3_test/test_sc/interop_test/iterator/IteratorValueAccess.py b/boa3_test/test_sc/interop_test/iterator/IteratorValueAccess.py index 3c0c8aac7..dc48789f9 100644 --- a/boa3_test/test_sc/interop_test/iterator/IteratorValueAccess.py +++ b/boa3_test/test_sc/interop_test/iterator/IteratorValueAccess.py @@ -7,8 +7,7 @@ @public def store(prefix: bytes, value: Any): - serialized_value = StdLib.serialize(value) - storage.put(prefix, serialized_value) + storage.put_object(prefix, value) @public diff --git a/boa3_test/test_sc/interop_test/runtime/ExecutingScriptHashOnDeploy.py b/boa3_test/test_sc/interop_test/runtime/ExecutingScriptHashOnDeploy.py index b6fd7da9f..fa6c02022 100644 --- a/boa3_test/test_sc/interop_test/runtime/ExecutingScriptHashOnDeploy.py +++ b/boa3_test/test_sc/interop_test/runtime/ExecutingScriptHashOnDeploy.py @@ -2,6 +2,7 @@ from boa3.builtin.compile_time import public from boa3.builtin.interop import runtime +from boa3.builtin.type import UInt160 from boa3.sc import storage @@ -12,5 +13,5 @@ def _deploy(data: Any, update: bool): @public -def get_script() -> bytes: - return storage.get(b'testKey') +def get_script() -> UInt160: + return storage.get_uint160(b'testKey') diff --git a/boa3_test/test_sc/while_test/WhileWithInteropCondition.py b/boa3_test/test_sc/while_test/WhileWithInteropCondition.py index 6908c0a2a..f4ddc61cd 100644 --- a/boa3_test/test_sc/while_test/WhileWithInteropCondition.py +++ b/boa3_test/test_sc/while_test/WhileWithInteropCondition.py @@ -4,7 +4,7 @@ from boa3.builtin.interop.contract import GAS, NEO from boa3.builtin.interop.runtime import executing_script_hash, notify from boa3.builtin.type import UInt160, helper as type_helper -from boa3.sc.storage import find, get, get_context, put +from boa3.sc.storage import find, get_uint160, get_context, put_uint160 FEE_RECEIVER_KEY = b'FEE_RECEIVER' @@ -14,7 +14,7 @@ @public def test_end_while_jump() -> bool: iterator = find(b'feesMap') - fee_receiver = get(FEE_RECEIVER_KEY) + fee_receiver = get_uint160(FEE_RECEIVER_KEY) while iterator.next(): token_bytes = cast(bytes, iterator.value[0]) token_bytes = token_bytes[7:] # cut 'feesMap' at the beginning of the bytes @@ -28,7 +28,7 @@ def test_end_while_jump() -> bool: @public def _deploy(data: Any, update: bool): # placeholders for testing - put(FEE_RECEIVER_KEY, UInt160()) + put_uint160(FEE_RECEIVER_KEY, UInt160()) feesMap.put(GAS, 10) feesMap.put(NEO, 20)