def get_state_change_with_balance_proof_by_locksroot( storage: SerializedSQLiteStorage, canonical_identifier: CanonicalIdentifier, locksroot: Locksroot, sender: Address, ) -> Optional[StateChangeRecord]: """Returns the state change which contains the corresponding balance proof. Use this function to find a balance proof for a call to unlock, which only happens after settle, so the channel has the unblinded version of the balance proof. """ filters: List[Dict[str, Any]] = list() filters.append({ "balance_proof.canonical_identifier.chain_identifier": str(canonical_identifier.chain_identifier), "balance_proof.canonical_identifier.token_network_address": to_hex_address(canonical_identifier.token_network_address), "balance_proof.canonical_identifier.channel_identifier": str(canonical_identifier.channel_identifier), "balance_proof.locksroot": to_hex(locksroot), "balance_proof.sender": to_hex_address(sender), }) query = FilteredDBQuery(filters=filters, main_operator=Operator.NONE, inner_operator=Operator.AND) return storage.get_latest_state_change_by_data_field(query)
def create_all_channels_for_network( app_channels: AppChannels, token_addresses: List[TokenAddress], channel_individual_deposit: TokenAmount, channel_settle_timeout: BlockTimeout, ) -> None: greenlets = set() for token_address in token_addresses: for app_pair in app_channels: greenlets.add( gevent.spawn( payment_channel_open_and_deposit, app_pair[0], app_pair[1], token_address, channel_individual_deposit, channel_settle_timeout, )) gevent.joinall(greenlets, raise_error=True) channels = [{ "app0": to_hex_address(app0.raiden.address), "app1": to_hex_address(app1.raiden.address), "deposit": channel_individual_deposit, "token_address": to_hex_address(token_address), } for (app0, app1), token_address in product(app_channels, token_addresses) ] log.info("Test channels", channels=channels)
def test_assumption_search_user_directory_returns_federated_users(chain_id, local_matrix_servers): """The search_user_directory should return federated users. This assumption test was added because of issue #5285. The path-finding-service was not functioning properly because the call to `search_user_directory` did not return federated users, only local users. Becaused of that the PFS assumed the users were offline and didn't find any valid routes for the payments. """ original_server_url = urlsplit(local_matrix_servers[0]).netloc room_alias = make_room_alias(chain_id, "broadcast_test") room_name_full = f"#{room_alias}:{original_server_url}" user_room_creator, _ = create_logged_in_client(local_matrix_servers[0]) user_room_creator.create_room(room_alias, is_public=True) user_federated, _ = create_logged_in_client(local_matrix_servers[1]) join_broadcast_room(user_federated, room_name_full) addresses = list() for _ in range(1000): user, signer = create_logged_in_client(local_matrix_servers[0]) join_broadcast_room(user, room_name_full) # Make sure to close the session instance, otherwise there will be too # many file descriptors opened by the underlying urllib3 connection # pool. user.api.session.close() del user addresses.append(signer.address) for address in addresses: assert user_federated.search_user_directory(to_hex_address(address))
def pack_reward_proof( chain_id: ChainID, token_network_address: TokenNetworkAddress, reward_amount: TokenAmount, monitoring_service_contract_address: MonitoringServiceAddress, non_closing_participant: Address, non_closing_signature: Signature, ) -> bytes: return proofs.pack_reward_proof( monitoring_service_contract_address=to_hex_address( monitoring_service_contract_address), chain_id=chain_id, token_network_address=to_hex_address(token_network_address), non_closing_participant=to_hex_address(non_closing_participant), non_closing_signature=non_closing_signature, reward_amount=reward_amount, )
def pack_withdraw( canonical_identifier: CanonicalIdentifier, participant: Address, total_withdraw: WithdrawAmount, expiration_block: BlockExpiration, ) -> bytes: """Packs withdraw data to be signed Packs the given arguments in a byte array in the same configuration the contracts expect the signed data to have. """ return proofs.pack_withdraw_message( token_network_address=to_hex_address( canonical_identifier.token_network_address), chain_identifier=canonical_identifier.chain_identifier, channel_identifier=canonical_identifier.channel_identifier, participant=to_hex_address(participant), amount_to_withdraw=TokenAmount(total_withdraw), expiration_block=expiration_block, )
def get_event_with_balance_proof_by_balance_hash( storage: SerializedSQLiteStorage, canonical_identifier: CanonicalIdentifier, balance_hash: BalanceHash, recipient: Address, ) -> Optional[EventRecord]: """Returns the event which contains the corresponding balance proof. Use this function to find a balance proof for a call to settle, which only has the blinded balance proof data. """ filters: List[Dict[str, Any]] = list() filter_items = { "canonical_identifier.chain_identifier": str(canonical_identifier.chain_identifier), "canonical_identifier.token_network_address": to_hex_address(canonical_identifier.token_network_address), "canonical_identifier.channel_identifier": str(canonical_identifier.channel_identifier), "balance_hash": to_hex(balance_hash), } balance_proof_filters = balance_proof_query_from_keys(prefix="", filters=filter_items) balance_proof_filters["recipient"] = to_hex_address(recipient) filters.append(balance_proof_filters) transfer_filters = balance_proof_query_from_keys(prefix="transfer.", filters=filter_items) transfer_filters["recipient"] = to_hex_address(recipient) filters.append(transfer_filters) query = FilteredDBQuery(filters=filters, main_operator=Operator.OR, inner_operator=Operator.AND) event = storage.get_latest_event_by_data_field(query) return event
def parallel_start_apps(raiden_apps: List[App]) -> None: """Start all the raiden apps in parallel.""" start_tasks = set() for app in raiden_apps: greenlet = gevent.spawn(app.raiden.start) greenlet.name = f"Fixture:raiden_network node:{to_checksum_address(app.raiden.address)}" start_tasks.add(greenlet) gevent.joinall(start_tasks, raise_error=True) addresses_in_order = { pos: to_hex_address(app.raiden.address) for pos, app in enumerate(raiden_apps) } log.info("Raiden Apps started", addresses_in_order=addresses_in_order)
def create_token( self, registry_address_hex: AddressHex, initial_alloc: int = 10**6, name: str = "raidentester", symbol: str = "RDT", decimals: int = 2, timeout: int = 60, auto_register: bool = True, ) -> AddressHex: """ Create a proxy for a new HumanStandardToken (ERC20), that is initialized with Args(below). Per default it will be registered with 'raiden'. Args: registry_address_hex: a hex encoded registry address. initial_alloc: amount of initial tokens. name: human readable token name. symbol: token shorthand symbol. decimals: decimal places. timeout: timeout in seconds for creation. auto_register: if True(default), automatically register the token with raiden. Returns: token_address_hex: the hex encoded address of the new token/token. """ with gevent.Timeout(timeout): contract_proxy, _ = self._raiden.rpc_client.deploy_single_contract( contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, contract=self._raiden.contract_manager.get_contract( CONTRACT_HUMAN_STANDARD_TOKEN), constructor_parameters=(initial_alloc, name, decimals, symbol), ) token_address = Address( to_canonical_address(contract_proxy.address)) token_address_hex = to_hex_address(token_address) if auto_register: self.register_token(registry_address_hex, token_address_hex) print("Successfully created {}the token '{}'.".format( "and registered " if auto_register else "", name)) return token_address_hex
def pack_balance_proof( nonce: Nonce, balance_hash: BalanceHash, additional_hash: AdditionalHash, canonical_identifier: CanonicalIdentifier, ) -> bytes: """Packs balance proof data to be signed Packs the given arguments in a byte array in the same configuration the contracts expect the signed data to have. """ return proofs.pack_balance_proof( token_network_address=to_hex_address( canonical_identifier.token_network_address), chain_identifier=canonical_identifier.chain_identifier, channel_identifier=canonical_identifier.channel_identifier, msg_type=MessageTypeId.BALANCE_PROOF, nonce=nonce, balance_hash=balance_hash, additional_hash=additional_hash, )
def test_canonical_identifier_validation(): invalid_chain_id = factories.make_canonical_identifier( chain_identifier="337") with pytest.raises(ValueError): invalid_chain_id.validate() wrong_type_channel_id = factories.make_canonical_identifier( channel_identifier="1") with pytest.raises(ValueError): wrong_type_channel_id.validate() negative_channel_id = factories.make_canonical_identifier( channel_identifier=-5) with pytest.raises(ValueError): negative_channel_id.validate() wrong_format_token_network_address = factories.make_canonical_identifier( token_network_address=to_hex_address( factories.UNIT_TOKEN_NETWORK_ADDRESS)) with pytest.raises(ValueError): wrong_format_token_network_address.validate()
def pack_signed_balance_proof( msg_type: MessageTypeId, nonce: Nonce, balance_hash: BalanceHash, additional_hash: AdditionalHash, canonical_identifier: CanonicalIdentifier, partner_signature: Signature, ) -> bytes: """Packs balance proof data to be signed for updateNonClosingBalanceProof Packs the given arguments in a byte array in the same configuration the contracts expect the signed data for updateNonClosingBalanceProof to have. """ return proofs.pack_balance_proof_message( token_network_address=to_hex_address( canonical_identifier.token_network_address), chain_identifier=canonical_identifier.chain_identifier, channel_identifier=canonical_identifier.channel_identifier, msg_type=msg_type, nonce=nonce, balance_hash=balance_hash, additional_hash=additional_hash, closing_signature=partner_signature, )
TODEVICE = "toDevice" # supports sending and receiving toDevice messages on Matrix class ServerListType(Enum): ACTIVE_SERVERS = "active_servers" ALL_SERVERS = "all_servers" # Set at 64 since parity's default is 64 and Geth's default is 128 # TODO: Make this configurable. Since in parity this is also a configurable value STATE_PRUNING_AFTER_BLOCKS = 64 STATE_PRUNING_SAFETY_MARGIN = 8 NO_STATE_QUERY_AFTER_BLOCKS = STATE_PRUNING_AFTER_BLOCKS - STATE_PRUNING_SAFETY_MARGIN NULL_ADDRESS_BYTES = bytes(20) NULL_ADDRESS_HEX = to_hex_address(Address(NULL_ADDRESS_BYTES)) NULL_ADDRESS_CHECKSUM = to_checksum_address(Address(NULL_ADDRESS_BYTES)) EMPTY_HASH = BlockHash(bytes(32)) EMPTY_BALANCE_HASH = BalanceHash(bytes(32)) EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32)) EMPTY_SIGNATURE = Signature(bytes(65)) EMPTY_SECRET = Secret(bytes(32)) EMPTY_SECRETHASH = SecretHash(bytes(32)) EMPTY_SECRET_SHA256 = sha256_secrethash(EMPTY_SECRET) LOCKSROOT_OF_NO_LOCKS = Locksroot(keccak(b"")) EMPTY_LOCKSROOT = Locksroot(bytes(32)) ZERO_TOKENS = TokenAmount(0) ABSENT_SECRET = Secret(b"")
def _serialize(self, value: Address, attr: Any, obj: Any, **kwargs: Any) -> str: return to_hex_address(value)
def _serialize(self, value: networkx.Graph, attr: Any, obj: Any, **kwargs: Any) -> str: return json.dumps([(to_hex_address(edge[0]), to_hex_address(edge[1])) for edge in value.edges])
def test_token_network_proxy(token_network_proxy, private_keys, token_proxy, chain_id, web3, contract_manager): assert token_network_proxy.settlement_timeout_min( ) == TEST_SETTLE_TIMEOUT_MIN assert token_network_proxy.settlement_timeout_max( ) == TEST_SETTLE_TIMEOUT_MAX token_network_address = to_canonical_address( token_network_proxy.proxy.address) c1_signer = LocalSigner(private_keys[1]) c1_client = JSONRPCClient(web3, private_keys[1]) c1_proxy_manager = ProxyManager( rpc_client=c1_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) c2_client = JSONRPCClient(web3, private_keys[2]) c2_proxy_manager = ProxyManager( rpc_client=c2_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) c2_signer = LocalSigner(private_keys[2]) c1_token_network_proxy = c1_proxy_manager.token_network( address=token_network_address, block_identifier=BLOCK_ID_LATEST) c2_token_network_proxy = c2_proxy_manager.token_network( address=token_network_address, block_identifier=BLOCK_ID_LATEST) initial_token_balance = 100 token_proxy.transfer(c1_client.address, initial_token_balance) token_proxy.transfer(c2_client.address, initial_token_balance) initial_balance_c1 = token_proxy.balance_of(c1_client.address) assert initial_balance_c1 == initial_token_balance initial_balance_c2 = token_proxy.balance_of(c2_client.address) assert initial_balance_c2 == initial_token_balance # instantiating a new channel - test basic assumptions assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, ) is None) msg = "Hex encoded addresses are not supported, an assertion must be raised" with pytest.raises(AssertionError): c1_token_network_proxy.get_channel_identifier( participant1=to_hex_address(c1_client.address), participant2=to_hex_address(c2_client.address), block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) msg = "Zero is not a valid channel_identifier identifier, an exception must be raised." with pytest.raises(InvalidChannelID): assert c1_token_network_proxy.channel_is_opened( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, channel_identifier=0, ) pytest.fail(msg) msg = "Zero is not a valid channel_identifier identifier. an exception must be raised." with pytest.raises(InvalidChannelID): assert c1_token_network_proxy.channel_is_closed( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, channel_identifier=0, ) pytest.fail(msg) msg = ("Opening a channel with a settle_timeout lower then token " "network's minimum will fail. This must be validated and the " "transaction must not be sent.") with pytest.raises(InvalidSettleTimeout): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN - 1, given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) # Using exactly the minimal timeout must succeed c1_token_network_proxy.new_netting_channel( partner=make_address(), settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) msg = ("Opening a channel with a settle_timeout larger then token " "network's maximum will fail. This must be validated and the " "transaction must not be sent.") with pytest.raises(InvalidSettleTimeout): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MAX + 1, given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) # Using exactly the maximal timeout must succeed c1_token_network_proxy.new_netting_channel( partner=make_address(), settle_timeout=TEST_SETTLE_TIMEOUT_MAX, given_block_identifier=BLOCK_ID_LATEST, ) msg = ( "Opening a channel with itself is not allow. This must be validated and " "the transaction must not be sent.") with pytest.raises(SamePeerAddress): c1_token_network_proxy.new_netting_channel( partner=c1_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) msg = "Trying a deposit to an inexisting channel must fail." with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=100, total_deposit=1, partner=c2_client.address, ) pytest.fail(msg) empty_balance_proof = BalanceProof( channel_identifier=100, token_network_address=c1_token_network_proxy.address, balance_hash=EMPTY_BALANCE_HASH, nonce=0, chain_id=chain_id, transferred_amount=0, ) closing_data = (empty_balance_proof.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF) + EMPTY_SIGNATURE) msg = "Trying to close an inexisting channel must fail." match = "The channel was not open at the provided block" with pytest.raises(RaidenUnrecoverableError, match=match): c1_token_network_proxy.close( channel_identifier=100, partner=c2_client.address, balance_hash=EMPTY_HASH, nonce=0, additional_hash=EMPTY_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=c1_signer.sign(data=closing_data), given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) channel_identifier, _, _ = c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) msg = "new_netting_channel did not return a valid channel id" assert isinstance(channel_identifier, T_ChannelID), msg msg = "multiple channels with the same peer are not allowed" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, ) is not None) assert (c1_token_network_proxy.channel_is_opened( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, ) is True) msg = "approve_and_set_total_deposit must fail if the amount exceed the account's balance" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=initial_token_balance + 1, partner=c2_client.address, ) pytest.fail(msg) msg = "approve_and_set_total_deposit must fail with a negative amount" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=-1, partner=c2_client.address, ) pytest.fail(msg) msg = "approve_and_set_total_deposit must fail with a zero amount" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=0, partner=c2_client.address, ) pytest.fail(msg) c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, ) transferred_amount = 3 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=token_network_address, nonce=1, chain_id=chain_id, transferred_amount=transferred_amount, ) signature = c1_signer.sign(data=balance_proof.serialize_bin()) balance_proof.signature = encode_hex(signature) signature_number = int.from_bytes(signature, "big") bit_to_change = random.randint(0, SIGNATURE_SIZE_IN_BITS - 1) signature_number_bit_flipped = signature_number ^ (2**bit_to_change) invalid_signatures = [ EMPTY_SIGNATURE, b"\x11" * 65, signature_number_bit_flipped.to_bytes(len(signature), "big"), ] msg = "close must fail if the closing_signature is invalid" for invalid_signature in invalid_signatures: closing_data = ( balance_proof.serialize_bin(msg_type=MessageTypeId.BALANCE_PROOF) + invalid_signature) with pytest.raises(RaidenUnrecoverableError): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof.balance_hash, nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=invalid_signature, closing_signature=c2_signer.sign(data=closing_data), given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) blocknumber_prior_to_close = c2_client.block_number() closing_data = balance_proof.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF) + decode_hex( balance_proof.signature) c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof.balance_hash, nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=decode_hex(balance_proof.signature), closing_signature=c2_signer.sign(data=closing_data), given_block_identifier=BLOCK_ID_LATEST, ) assert (c1_token_network_proxy.channel_is_closed( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, ) is True) assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, ) is not None) msg = ( "given_block_identifier is the block at which the transaction is being " "sent. If the channel is already closed at that block the client code " "has a programming error. An exception is raised for that.") with pytest.raises(RaidenUnrecoverableError): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof.balance_hash, nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=decode_hex(balance_proof.signature), closing_signature=c2_signer.sign(data=closing_data), given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) msg = ("The channel cannot be closed two times. If it was not closed at " "given_block_identifier but it is closed at the time the proxy is " "called an exception must be raised.") with pytest.raises(RaidenRecoverableError): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof.balance_hash, nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=decode_hex(balance_proof.signature), closing_signature=c2_signer.sign(data=closing_data), given_block_identifier=blocknumber_prior_to_close, ) pytest.fail(msg) msg = "depositing to a closed channel must fail" match = "closed" with pytest.raises(RaidenRecoverableError, match=match): c2_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=blocknumber_prior_to_close, channel_identifier=channel_identifier, total_deposit=20, partner=c1_client.address, ) pytest.fail(msg) c1_client.wait_until_block(target_block_number=c1_client.block_number() + TEST_SETTLE_TIMEOUT_MIN) invalid_transferred_amount = 1 msg = "settle with invalid transferred_amount data must fail" with pytest.raises(BrokenPreconditionError): c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=invalid_transferred_amount, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier=BLOCK_ID_LATEST, ) assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier=BLOCK_ID_LATEST, ) is None) assert token_proxy.balance_of(c1_client.address) == (initial_balance_c1 - transferred_amount) assert token_proxy.balance_of(c2_client.address) == (initial_balance_c2 + transferred_amount) msg = "depositing to a settled channel must fail" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, ) pytest.fail(msg)
def address_hex(self) -> AddressHex: return to_hex_address(self.address)