Skip to content

Commit

Permalink
Extrinsic encode issues (#107)
Browse files Browse the repository at this point in the history
* Extract Address and Signature using common UncheckedExtrinsic namespace

* Accept single value to encode Struct with one field
  • Loading branch information
arjanz authored Feb 28, 2023
1 parent 7c2bce7 commit 71de293
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 23 deletions.
47 changes: 27 additions & 20 deletions scalecodec/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,35 +532,42 @@ def add_portable_registry(self, metadata: 'GenericMetadataVersioned', prefix=Non

# Process extrinsic type in metadata to register correct Address and ExtrinsicSignature types
try:
extrinsic_type_id = metadata[1][1]['extrinsic']['ty'].value
# Retrieve Extrinsic using common namespace
extrinsic_type = self.get_decoder_class("sp_runtime::generic::unchecked_extrinsic::UncheckedExtrinsic")

extrinsic_type = self.get_decoder_class(f"{prefix}::{extrinsic_type_id}")
# Try to fall back on extrinsic type in metadata
if extrinsic_type is None:
extrinsic_type_id = metadata[1][1]['extrinsic']['ty'].value
extrinsic_type = self.get_decoder_class(f"{prefix}::{extrinsic_type_id}")

types_dict = {}
if extrinsic_type is not None:
# Extract Address and Signature type and set in type registry

for param in extrinsic_type.scale_info_type.value['params']:
if param['name'] == 'Address':
types_dict = {}

type_string = f'{prefix}::{param["type"]}'
for param in extrinsic_type.scale_info_type.value['params']:
if param['name'] == 'Address':

types_dict['Address'] = type_string
types_dict['AccountId'] = type_string
types_dict['LookupSource'] = type_string
type_string = f'{prefix}::{param["type"]}'

# Check if Address is MultiAddress
addres_type = self.get_decoder_class(type_string)
types_dict['Address'] = type_string
types_dict['AccountId'] = type_string
types_dict['LookupSource'] = type_string

if addres_type is self.get_decoder_class('sp_runtime::multiaddress::MultiAddress'):
for address_param in addres_type.scale_info_type.value['params']:
if address_param['name'] == 'AccountId':
# Set AccountId
types_dict['AccountId'] = f'{prefix}::{address_param["type"]}'
# Check if Address is MultiAddress
addres_type = self.get_decoder_class(type_string)

elif param['name'] == 'Signature':
types_dict['ExtrinsicSignature'] = f'{prefix}::{param["type"]}'
if addres_type is self.get_decoder_class('sp_runtime::multiaddress::MultiAddress'):
for address_param in addres_type.scale_info_type.value['params']:
if address_param['name'] == 'AccountId':
# Set AccountId
types_dict['AccountId'] = f'{prefix}::{address_param["type"]}'

# Update type registry
self.update_type_registry_types(types_dict)
elif param['name'] == 'Signature':
types_dict['ExtrinsicSignature'] = f'{prefix}::{param["type"]}'

# Update type registry
self.update_type_registry_types(types_dict)
except NotImplementedError:
pass

Expand Down
11 changes: 9 additions & 2 deletions scalecodec/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,14 +577,21 @@ def process(self):

return result

def process_encode(self, value: Union[dict, tuple]) -> ScaleBytes:
def process_encode(self, value: Union[dict, tuple, str, int, bool]) -> ScaleBytes:
data = ScaleBytes(bytearray())

self.value_object = {}

if type(value) in (str, int, bool):
# Convert to tuple with one element
value = (value,)

if type(value) is tuple:
# Convert tuple to dict
value = {key: value[idx] for idx, (key, _) in enumerate(self.type_mapping)}
try:
value = {key: value[idx] for idx, (key, _) in enumerate(self.type_mapping)}
except IndexError:
raise ValueError("Not enough items in tuple to match type_mapping")

for key, data_type in self.type_mapping:
if key not in value:
Expand Down
13 changes: 12 additions & 1 deletion test/test_type_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,21 @@ def test_struct_encode_tuple(self):
})

obj = TestStruct()

data = obj.encode((4, 2))

self.assertEqual(ScaleBytes("0x0400000002000000"), data)

def test_struct_encode_int(self):

TestStruct = type('TestStruct', (Struct,), {
'type_mapping': (('nonce', 'u32'),)
})

obj = TestStruct()
data = obj.encode(1)

self.assertEqual(ScaleBytes("0x01000000"), data)

# def test_struct_raw_encode(self):
# RuntimeConfiguration().update_type_registry_types({
# "TestKeys": {
Expand Down

0 comments on commit 71de293

Please sign in to comment.