Skip to content

Commit ddb5caa

Browse files
committed
Fixed ScaleType serialization issues with Array and HashMap types
1 parent a11a6e3 commit ddb5caa

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

scalecodec/base.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ def new(self, **kwargs) -> 'ScaleType':
164164

165165
return obj
166166

167-
168167
def impl(self, scale_type_cls: type = None, runtime_config=None) -> 'ScaleTypeDef':
169168
"""
170169
@@ -286,7 +285,7 @@ def deserialize(self, value_serialized: any):
286285
return self.value_object
287286

288287
self.value_object = self.type_def.deserialize(value_serialized)
289-
self.value_serialized = value_serialized
288+
self.value_serialized = self.type_def.serialize(self.value_object)
290289

291290
return self.value_object
292291

scalecodec/types.py

+58-8
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,18 @@ def deserialize(self, value: str) -> str:
655655
return value
656656

657657

658+
class ArrayObject(ScaleType):
659+
660+
def to_bytes(self) -> bytes:
661+
if self.type_def.type_def is not U8:
662+
raise ScaleDeserializeException('Only an Array of U8 can be represented as bytes')
663+
return self.value_object
664+
665+
658666
class Array(ScaleTypeDef):
667+
668+
scale_type_cls = ArrayObject
669+
659670
def __init__(self, type_def: ScaleTypeDef, length: int):
660671
self.type_def = type_def
661672
self.length = length
@@ -715,12 +726,27 @@ def serialize(self, value: Union[list, bytes]) -> Union[list, str]:
715726
return f'0x{value.hex()}'
716727

717728
def deserialize(self, value: Union[list, str, bytes]) -> Union[list, bytes]:
729+
730+
if type(value) not in [list, str, bytes]:
731+
raise ScaleDeserializeException('value should be of type list, str or bytes')
732+
718733
if type(value) is str:
719734
if value[0:2] == '0x':
720-
return bytes.fromhex(value[2:])
735+
value = bytes.fromhex(value[2:])
721736
else:
722-
return value.encode()
723-
else:
737+
value = value.encode()
738+
739+
if len(value) != self.length:
740+
raise ScaleDeserializeException('Length of array does not match size of value')
741+
742+
if type(value) is bytes:
743+
if self.type_def is not U8:
744+
raise ScaleDeserializeException('Only an Array of U8 can be represented as (hex)bytes')
745+
746+
return value
747+
748+
if type(value) is list:
749+
724750
value_object = []
725751

726752
for item in value:
@@ -793,7 +819,13 @@ def decode(self, data: ScaleBytes) -> list:
793819
return value
794820

795821
def serialize(self, value: list) -> list:
796-
return [(k.value_serialized, v.value_serialized) for k, v in value]
822+
output = []
823+
for k, v in value:
824+
if type(k) is ScaleType and type(v) is ScaleType:
825+
output.append((k.value_serialized, v.value_serialized))
826+
else:
827+
output.append((k, v))
828+
return output
797829

798830
def deserialize(self, value: list) -> list:
799831
return [(self.key_def.deserialize(k), self.value_def.deserialize(v)) for k, v in value]
@@ -833,12 +865,20 @@ def decode(self, data: ScaleBytes) -> bytearray:
833865
def serialize(self, value: bytearray) -> str:
834866
return f'0x{value.hex()}'
835867

836-
def deserialize(self, value: str) -> bytearray:
837-
if type(value) is str:
868+
def deserialize(self, value: Union[bytes, str, list]) -> bytes:
869+
870+
if type(value) in (list, bytearray):
871+
value = bytes(value)
872+
873+
elif type(value) is str:
838874
if value[0:2] == '0x':
839-
value = bytearray.fromhex(value[2:])
875+
value = bytes.fromhex(value[2:])
840876
else:
841877
value = value.encode('utf-8')
878+
879+
if type(value) is not bytes:
880+
raise ScaleDeserializeException(f'Cannot deserialize type "{type(value)}"')
881+
842882
return value
843883

844884
def example_value(self, _recursion_level: int = 0, max_recursion: int = TYPE_DECOMP_MAX_RECURSIVE):
@@ -860,13 +900,19 @@ def serialize(self, value: str) -> str:
860900
def deserialize(self, value: str) -> str:
861901
return value
862902

863-
864903
def create_example(self, _recursion_level: int = 0):
865904
return 'String'
866905

867906

907+
class HashDefObject(ScaleType):
908+
def to_bytes(self) -> bytes:
909+
return self.value_object
910+
911+
868912
class HashDef(ScaleTypeDef):
869913

914+
scale_type_cls = HashDefObject
915+
870916
def __init__(self, bits: int):
871917
super().__init__()
872918
self.bits = bits
@@ -897,6 +943,10 @@ def serialize(self, value: bytes) -> str:
897943
def deserialize(self, value: Union[str, bytes]) -> bytes:
898944
if type(value) is str:
899945
value = bytes.fromhex(value[2:])
946+
947+
if type(value) is not bytes:
948+
raise ScaleDeserializeException('value should be of type str or bytes')
949+
900950
return value
901951

902952
def example_value(self, _recursion_level: int = 0, max_recursion: int = TYPE_DECOMP_MAX_RECURSIVE):

test/test_boolean.py

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ def test_bool_encode_decode(self):
4747

4848
self.assertEqual(value, scale_obj.value)
4949

50+
def test_bool_encode_false(self):
51+
scale_obj = Bool().new()
52+
data = scale_obj.encode(False)
53+
self.assertEqual(ScaleBytes("0x00"), data)
54+
5055

5156
if __name__ == '__main__':
5257
unittest.main()

0 commit comments

Comments
 (0)