def process(self): self.process_compact_bytes() if self.sub_type: byte_data = self.get_decoder_class( type_string=self.sub_type, data=ScaleBytes(self.compact_bytes), runtime_config=self.runtime_config).process() if type(byte_data) is int and self.compact_length <= 4: return int(byte_data / 4) else: return byte_data else: return self.compact_bytes
def accumulation_hook(self, db_session): self.block.count_log = len(self.block.logs) for idx, log_data in enumerate(self.block.logs): log_digest = LogDigest(ScaleBytes(log_data)) log_digest.decode() log = Log( block_id=self.block.id, log_idx=idx, type_id=log_digest.index, type=log_digest.index_value, data=log_digest.value, ) log.save(db_session)
def process(self): self.process_compact_bytes() if self.sub_type: byte_data = self.get_decoder_class( self.sub_type, ScaleBytes(self.compact_bytes)).process() # TODO Assumptions if type(byte_data) is int and self.compact_length <= 4: return int(byte_data / 4) else: # TODO raise exception? return byte_data else: return self.compact_bytes
def process_encode(self, value): if type(value) is not list: raise ValueError("Provided value is not a list of booleans") if len(value) == 0: return ScaleBytes(b'\x00') int_value = sum(v << i for i, v in enumerate(value)) # encode the length in a compact u32 compact_obj = CompactU32() data = compact_obj.encode(len(value)) byte_length = math.ceil(len(value) / 8) return data + int_value.to_bytes(length=byte_length, byteorder='little')
def process_encode(self, value): if type(value) is not dict: raise TypeError( "value must be of type dict to encode a GenericCall") # Check requirements if 'call_index' in value: self.call_index = value['call_index'] elif 'call_module' in value and 'call_function' in value: # Look up call module from metadata for call_index, ( call_module, call_function) in self.metadata.call_index.items(): if call_module.name == value[ 'call_module'] and call_function.name == value[ 'call_function']: self.call_index = call_index self.call_module = call_module self.call_function = call_function break if not self.call_index: raise ValueError( 'Specified call module and function not found in metadata') elif not self.call_module or not self.call_function: raise ValueError('No call module and function specified') data = ScaleBytes(bytearray.fromhex(self.call_index)) # Encode call params if len(self.call_function.args) > 0: for arg in self.call_function.args: if arg.name not in value['call_args']: raise ValueError('Parameter \'{}\' not specified'.format( arg.name)) else: param_value = value['call_args'][arg.name] arg_obj = self.get_decoder_class(arg.type, metadata=self.metadata) data += arg_obj.encode(param_value) return data
def process_encode(self, value): if type(value) is list: value = sum(v << i for i, v in enumerate(reversed(value))) if type(value) is not int: raise ValueError("Provided value is not an int or a list of booleans") if value == 0: return ScaleBytes(b'\x00') # encode the length in a compact u32 compact_obj = CompactU32() data = compact_obj.encode(value.bit_length()) byte_length = math.ceil(value.bit_length() / 8) return data + value.to_bytes(length=byte_length, byteorder='little')
def process_encode(self, value): if type(value) == str and value[0:2] != '0x': # Assume SS58 encoding address if len(value) >= 46: from scalecodec.utils.ss58 import ss58_decode value = '0x{}'.format(ss58_decode(value)) else: from scalecodec.utils.ss58 import ss58_decode_account_index index_obj = GenericAccountIndex() value = index_obj.encode(ss58_decode_account_index(value)) if type(value) == str and value[0:2] == '0x' and len(value) == 66: # value is AccountId return ScaleBytes('0x{}'.format(value[2:])) elif type(value) == int: # value is AccountIndex raise NotImplementedError('Encoding of AccountIndex Adresses not supported yet') else: raise ValueError('Value is in unsupported format, expected 32 bytes hex-string for AccountIds or int for AccountIndex')
def setUpClass(cls): module_path = os.path.dirname(__file__) # scale_info_defaults = load_type_registry_file(os.path.join(module_path, 'fixtures', 'scale_info_defaults.json')) cls.runtime_config = RuntimeConfigurationObject(ss58_format=42) cls.runtime_config.update_type_registry( load_type_registry_preset("metadata_types")) # cls.runtime_config.update_type_registry(scale_info_defaults) cls.metadata_fixture_dict = load_type_registry_file( os.path.join(module_path, 'fixtures', 'metadata_hex.json')) cls.metadata_obj = cls.runtime_config.create_scale_object( 'MetadataVersioned', data=ScaleBytes(cls.metadata_fixture_dict['V14'])) cls.metadata_obj.decode() cls.runtime_config.add_portable_registry(cls.metadata_obj)
def test_box_call(self): RuntimeConfiguration().update_type_registry( load_type_registry_preset("default")) scale_value = ScaleBytes( "0x0400006e57561de4b4e63f0af8bf336008252a9597e5cdcb7622c72de4ff39731c5402070010a5d4e8" ) obj = RuntimeConfiguration().create_scale_object( 'Box<Call>', scale_value, metadata=self.metadata_decoder) value = obj.decode() self.assertEqual(value['call_function'], 'transfer') self.assertEqual(value['call_module'], 'Balances') self.assertEqual( value['call_args'][0]['value'], '0x6e57561de4b4e63f0af8bf336008252a9597e5cdcb7622c72de4ff39731c5402' ) self.assertEqual(value['call_args'][1]['value'], 1000000000000)
def test_weak_bounded_vec(self): # 87 = ['frame_support', 'storage', 'weak_bounded_vec', 'WeakBoundedVec'] obj = self.runtime_config.create_scale_object( 'scale_info::318', ScaleBytes( "0x0401020304050607080a00000000000000000000000000000000")) obj.decode() self.assertEqual([{ "id": "0x0102030405060708", 'amount': 10, 'reasons': "Fee" }], obj.value) data = obj.encode([{ "id": "0x0102030405060708", 'amount': 10, 'reasons': "Fee" }]) self.assertEqual( '0x0401020304050607080a00000000000000000000000000000000', data.to_hex())
def get_block_events(self, block_hash: str) -> list: """Find `Request` events for the given `block_hash`. Args: block_hash (str): block hash for which to find event. Returns: list: list of tuples (event, decoded_event), where `event` represents a raw `Request` events and `decoded_event` is a dict of the decoded event. """ substrate = self.get_connection() spec_version = substrate.get_block_runtime_version(block_hash).get( "specVersion", 0) # Obtain metadata metadata = substrate.get_block_metadata(block_hash, spec_version) contract_metadata = ContractMetadata.create_from_file( self.metadata_file, substrate) # Iterate through raw events in the block new_events = [] for event in substrate.get_block_events(block_hash, metadata).elements: if (event.event_module.name == "Contracts" and event.event.name == "ContractExecution"): contract_event_obj = ContractEvent( data=ScaleBytes(event.params[1]["value"]), runtime_config=substrate.runtime_config, contract_metadata=contract_metadata, ) decoded_event = contract_event_obj.decode() # Request event was found, add it to the list if decoded_event["name"] == "Request": if (substrate.ss58_encode(event.params[0]["value"]) in self.tracked_contracts): new_events.append((event, decoded_event)) return new_events
def process_metadata_type(self, type_string, spec_version): runtime_type = RuntimeType.query(self.db_session).filter_by( type_string=type_string, spec_version=spec_version).first() if not runtime_type: # Get current Runtime configuration try: # TODO move logic to RuntimeConfiguration.get_decoder_class # TODO FIX ScaleBytes('0x00') does not process Option<*> properly decoder_obj = ScaleDecoder.get_decoder_class( type_string, ScaleBytes('0x00')) if decoder_obj.sub_type: # Also process sub type if ',' in decoder_obj.sub_type and decoder_obj.sub_type[ -1:] not in ['>', ')']: for sub_type in decoder_obj.sub_type.split(','): self.process_metadata_type(sub_type.strip(), spec_version) else: self.process_metadata_type(decoder_obj.sub_type, spec_version) decoder_class_name = decoder_obj.__class__.__name__ except NotImplementedError: decoder_class_name = '[not implemented]' runtime_type = RuntimeType( spec_version=spec_version, type_string=type_string, decoder_class=decoder_class_name, ) runtime_type.save(self.db_session)
def test_enum_no_value(self): obj = self.runtime_config.create_scale_object('scale_info::21', ScaleBytes("0x02")) obj.decode() self.assertEqual('CodeUpdated', obj.value)
def test_str_representation(self): obj = ScaleDecoder.get_decoder_class('Bytes', ScaleBytes("0x1054657374")) obj.decode() self.assertEqual(str(obj), "Test")
def test_no_more_bytes_available(self): obj = ScaleDecoder.get_decoder_class('[u8; 4]', ScaleBytes("0x010203")) self.assertRaises(RemainingScaleBytesNotEmptyException, obj.decode, False)
def test_scale_decoder_remaining_bytes(self): obj = ScaleDecoder.get_decoder_class('[u8; 3]', ScaleBytes("0x010203")) self.assertEqual(obj.get_remaining_bytes(), b"\x01\x02\x03")
def test_add_scalebytes(self): scale_total = ScaleBytes("0x0102") + "0x0304" self.assertEqual(scale_total.data, bytearray.fromhex("01020304"))
def test_reset(self): scale = ScaleBytes("0x01020304") scale.get_next_bytes(1) scale.reset() self.assertEqual(scale.get_remaining_bytes(), b'\x01\x02\x03\x04')
def test_validatorprefs_struct(self): obj = ScaleDecoder.get_decoder_class('ValidatorPrefsLegacy', ScaleBytes("0x0c00")) obj.decode() self.assertEqual(obj.value, {'unstakeThreshold': 3, 'validatorPayment': 0})
def process_encode(self, value): if value[0:2] != '0x' or len(value) != 130: raise ValueError('Value should start with "0x" and should be 64 bytes long') return ScaleBytes(value)
def process_encode(self, value): if -2**256 <= int(value) <= 2**256-1: return ScaleBytes(bytearray(int(value).to_bytes(32, 'little', signed=True))) else: raise ValueError('{} out of range for i256'.format(value))
def test_compact_bool_false(self): obj = ScaleDecoder.get_decoder_class('bool', ScaleBytes("0x00")) obj.decode() self.assertEqual(obj.value, False)
def process_encode(self, value): if 0 <= int(value) <= 2**128 - 1: return ScaleBytes(bytearray(int(value).to_bytes(16, 'little'))) else: raise ValueError('{} out of range for u128'.format(value))
def process_encode(self, value): return ScaleBytes(bytearray())
def test_tuple(self): obj = self.runtime_config.create_scale_object( 'scale_info::73', ScaleBytes("0x0400000003000000")) obj.decode() self.assertEqual((4, 3), obj.value)
def test_bytes_data_format(self): obj = ScaleDecoder.get_decoder_class('Compact<u32>', ScaleBytes(b"\x02\x09\x3d\x00")) obj.decode() self.assertEqual(obj.value, 1000000)
def process_encode(self, value): if -32768 <= int(value) <= 32767: return ScaleBytes(bytearray(int(value).to_bytes(2, 'little', signed=True))) else: raise ValueError('{} out of range for i16'.format(value))
def test_compact_bool_invalid(self): obj = ScaleDecoder.get_decoder_class('bool', ScaleBytes("0x02")) self.assertRaises(InvalidScaleTypeValueException, obj.decode)
def on_post(self, req, resp): metadata = MetadataDecoder(ScaleBytes(req.media.get('result'))) resp.status = falcon.HTTP_200 resp.media = metadata.process()
def process_encode(self, value): if -2147483648 <= int(value) <= 2147483647: return ScaleBytes(bytearray(int(value).to_bytes(4, 'little', signed=True))) else: raise ValueError('{} out of range for i32'.format(value))