def set_url(self, url: str) -> TransactionHash: """Sets the url needed to access the service via HTTP for the caller""" if not url.strip(): msg = "Invalid empty URL" raise BrokenPreconditionError(msg) parsed_url = urlparse(url) if parsed_url.scheme not in ("http", "https"): msg = "URL provided to service registry must be a valid HTTP(S) endpoint." raise BrokenPreconditionError(msg) extra_log_details: Dict[str, Any] = {} estimated_transaction = self.client.estimate_gas( self.proxy, "setURL", extra_log_details, url) if estimated_transaction is None: msg = f"URL {url} is invalid" raise RaidenUnrecoverableError(msg) transaction_sent = self.client.transact(estimated_transaction) transaction_mined = self.client.poll_transaction(transaction_sent) if not was_transaction_successfully_mined(transaction_mined): msg = f"URL {url} is invalid" raise RaidenUnrecoverableError(msg) else: return transaction_mined.transaction_hash
def set_url(self, url: str) -> None: """Sets the url needed to access the service via HTTP for the caller""" log_details: Dict[str, Any] = { "node": to_checksum_address(self.node_address), "contract": to_checksum_address(self.address), "url": url, } if not url.strip(): msg = "Invalid empty URL" raise BrokenPreconditionError(msg) parsed_url = urlparse(url) if parsed_url.scheme not in ("http", "https"): msg = "URL provided to service registry must be a valid HTTP(S) endpoint." raise BrokenPreconditionError(msg) with log_transaction(log, "set_url", log_details): gas_limit = self.proxy.estimate_gas("latest", "setURL", url) if not gas_limit: msg = f"URL {url} is invalid" raise RaidenUnrecoverableError(msg) log_details["gas_limit"] = gas_limit transaction_hash = self.proxy.transact("setURL", gas_limit, url) receipt = self.client.poll(transaction_hash) failed_receipt = check_transaction_threw(receipt=receipt) if failed_receipt: msg = f"URL {url} is invalid" raise RaidenUnrecoverableError(msg)
def _check_channel_state_for_deposit( self, participant1, participant2, channel_identifier, deposit_amount, ): participant_details = self.detail_participants( participant1, participant2, channel_identifier, ) channel_state = self._get_channel_state( participant1=self.node_address, participant2=participant2, channel_identifier=channel_identifier, ) # Check if deposit is being made on a nonexistent channel if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED): raise RaidenUnrecoverableError( f'Channel between participant {participant1} ' f'and {participant2} does not exist', ) # Deposit was prohibited because the channel is settled elif channel_state == ChannelState.SETTLED: raise RaidenUnrecoverableError( 'Deposit is not possible due to channel being settled', ) # Deposit was prohibited because the channel is closed elif channel_state == ChannelState.CLOSED: raise RaidenRecoverableError('Channel is already closed', ) elif participant_details.our_details.deposit < deposit_amount: raise RaidenUnrecoverableError('Deposit amount decreased')
def _check_channel_state_for_withdraw( self, participant1, participant2, channel_identifier, withdraw_amount, ): participant_details = self.detail_participants( participant1, participant2, channel_identifier, ) if participant_details.our_details.withdrawn > withdraw_amount: raise WithdrawMismatch('Withdraw amount decreased') channel_state = self._get_channel_state( participant1=participant1, participant2=participant2, channel_identifier=channel_identifier, ) if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED): raise RaidenUnrecoverableError( f'Channel between participant {participant1} ' f'and {participant2} does not exist', ) elif channel_state == ChannelState.SETTLED: raise RaidenUnrecoverableError( 'A settled channel cannot be closed', ) elif channel_state == ChannelState.CLOSED: raise RaidenRecoverableError('Channel is already closed', )
def _check_channel_state_for_settle( self, participant1: typing.Address, participant2: typing.Address, channel_identifier: typing.ChannelID, ) -> None: channel_data = self.detail_channel(participant1, participant2, channel_identifier) if channel_data.state == ChannelState.SETTLED: raise RaidenRecoverableError('Channel is already settled', ) elif channel_data.state == ChannelState.REMOVED: raise RaidenRecoverableError( 'Channel is already unlocked. It cannot be settled', ) elif channel_data.state == ChannelState.OPENED: raise RaidenUnrecoverableError( 'Channel is still open. It cannot be settled', ) elif channel_data.state == ChannelState.CLOSED: if self.client.block_number() < channel_data.settle_block_number: raise RaidenUnrecoverableError( 'Channel cannot be settled before settlement window is over', ) raise RaidenUnrecoverableError( "Settling this channel failed although the channel's current state " "is closed.", )
def handle_contract_send_channelwithdraw( raiden: "RaidenService", channel_withdraw_event: ContractSendChannelWithdraw ) -> None: withdraw_confirmation_data = pack_withdraw( canonical_identifier=channel_withdraw_event.canonical_identifier, participant=raiden.address, total_withdraw=channel_withdraw_event.total_withdraw, expiration_block=channel_withdraw_event.expiration, ) our_signature = raiden.signer.sign(data=withdraw_confirmation_data) chain_state = state_from_raiden(raiden) confirmed_block_identifier = chain_state.block_hash channel_state = get_channelstate_by_canonical_identifier( chain_state=chain_state, canonical_identifier=channel_withdraw_event.canonical_identifier, ) if channel_state is None: raise RaidenUnrecoverableError("ContractSendChannelWithdraw for non-existing channel.") channel_proxy = raiden.proxy_manager.payment_channel( channel_state=channel_state, block_identifier=confirmed_block_identifier ) try: channel_proxy.set_total_withdraw( total_withdraw=channel_withdraw_event.total_withdraw, expiration_block=channel_withdraw_event.expiration, participant_signature=our_signature, partner_signature=channel_withdraw_event.partner_signature, block_identifier=channel_withdraw_event.triggered_by_block_hash, ) except InsufficientEth as e: raise RaidenUnrecoverableError(str(e)) from e
def handle_contract_send_channelupdate( raiden: "RaidenService", channel_update_event: ContractSendChannelUpdateTransfer) -> None: balance_proof = channel_update_event.balance_proof if balance_proof: canonical_identifier = balance_proof.canonical_identifier chain_state = state_from_raiden(raiden) confirmed_block_identifier = chain_state.block_hash channel_state = get_channelstate_by_canonical_identifier( chain_state=chain_state, canonical_identifier=canonical_identifier) if channel_state is None: raise RaidenUnrecoverableError( "ContractSendChannelUpdateTransfer for inexesting channel." ) channel = raiden.proxy_manager.payment_channel( channel_state=channel_state, block_identifier=confirmed_block_identifier) non_closing_data = pack_signed_balance_proof( msg_type=MessageTypeId.BALANCE_PROOF_UPDATE, nonce=balance_proof.nonce, balance_hash=balance_proof.balance_hash, additional_hash=balance_proof.message_hash, canonical_identifier=canonical_identifier, partner_signature=balance_proof.signature, ) our_signature = raiden.signer.sign(data=non_closing_data) try: channel.update_transfer( nonce=balance_proof.nonce, balance_hash=balance_proof.balance_hash, additional_hash=balance_proof.message_hash, partner_signature=balance_proof.signature, signature=our_signature, block_identifier=channel_update_event. triggered_by_block_hash, ) except InsufficientEth as e: raise RaidenUnrecoverableError( f"{str(e)}\n" "CAUTION: This happened when updating our side of the channel " "during a channel settlement. You are in immediate danger of " "losing funds in this channel.") from e
def deposit(self, block_identifier: BlockSpecification, limit_amount: TokenAmount) -> None: """Makes a deposit to create or extend a registration""" gas_limit = self.proxy.estimate_gas(block_identifier, "deposit", limit_amount) if not gas_limit: msg = "ServiceRegistry.deposit transaction fails" raise RaidenUnrecoverableError(msg) transaction_hash = self.proxy.transact("deposit", gas_limit, limit_amount) receipt = self.client.poll(transaction_hash) failed_receipt = check_transaction_threw(receipt=receipt) if failed_receipt: msg = "ServiceRegistry.deposit transaction failed" raise RaidenUnrecoverableError(msg)
def channel_state_until_state_change( raiden: "RaidenService", canonical_identifier: CanonicalIdentifier, state_change_identifier: StateChangeID, ) -> Optional[NettingChannelState]: # pragma: no unittest """ Go through WAL state changes until a certain balance hash is found. """ assert raiden.wal, "Raiden has not been started yet" wal = restore_to_state_change( transition_function=node.state_transition, storage=raiden.wal.storage, state_change_identifier=state_change_identifier, node_address=raiden.address, ) msg = "There is a state change, therefore the state must not be None" assert wal.state_manager.current_state is not None, msg chain_state = wal.state_manager.current_state channel_state = views.get_channelstate_by_canonical_identifier( chain_state=chain_state, canonical_identifier=canonical_identifier) if not channel_state: raise RaidenUnrecoverableError( f"Channel was not found before state_change {state_change_identifier}" ) return channel_state
def _get_onchain_locksroots( raiden: RaidenService, storage: SQLiteStorage, token_network: Dict[str, Any], channel: Dict[str, Any], ) -> Tuple[Locksroot, Locksroot]: channel_new_state_change = _find_channel_new_state_change( storage=storage, token_network_address=token_network['address'], channel_identifier=channel['identifier'], ) if not channel_new_state_change: raise RaidenUnrecoverableError( f'Could not find the state change for channel {channel["identifier"]}, ' f'token network address: {token_network["address"]} being created. ', ) canonical_identifier = CanonicalIdentifier( chain_identifier=CHAIN_ID_UNSPECIFIED, token_network_address=to_canonical_address(token_network['address']), channel_identifier=int(channel['identifier']), ) our_locksroot, partner_locksroot = get_onchain_locksroots( chain=raiden.chain, canonical_identifier=canonical_identifier, participant1=to_canonical_address(channel['our_state']['address']), participant2=to_canonical_address(channel['partner_state']['address']), block_identifier='latest', ) return our_locksroot, partner_locksroot
def _get_onchain_locksroots( raiden: "RaidenService", storage: SQLiteStorage, token_network: Dict[str, Any], channel: Dict[str, Any], ) -> Tuple[Locksroot, Locksroot]: channel_new_state_change = _find_channel_new_state_change( storage=storage, token_network_address=token_network["address"], channel_identifier=channel["identifier"], ) if not channel_new_state_change: raise RaidenUnrecoverableError( f'Could not find the state change for channel {channel["identifier"]}, ' f'token network address: {token_network["address"]} being created. ' ) canonical_identifier = CanonicalIdentifier( chain_identifier=ChainID(-1), token_network_address=TokenNetworkAddress( to_canonical_address(token_network["address"])), channel_identifier=ChannelID(int(channel["identifier"])), ) our_locksroot, partner_locksroot = get_onchain_locksroots( chain=raiden.chain, canonical_identifier=canonical_identifier, participant1=to_canonical_address(channel["our_state"]["address"]), participant2=to_canonical_address(channel["partner_state"]["address"]), block_identifier="latest", ) return our_locksroot, partner_locksroot
def channel_state_until_state_change( raiden, payment_network_identifier: typing.PaymentNetworkID, token_address: typing.TokenAddress, channel_identifier: typing.ChannelID, state_change_identifier: int, ) -> typing.Optional[NettingChannelState]: """ Go through WAL state changes until a certain balance hash is found. """ wal = restore_to_state_change( transition_function=node.state_transition, storage=raiden.wal.storage, state_change_identifier=state_change_identifier, ) msg = 'There is a state change, therefore the state must not be None' assert wal.state_manager.current_state is not None, msg channel_state = views.get_channelstate_by_id( chain_state=wal.state_manager.current_state, payment_network_id=payment_network_identifier, token_address=token_address, channel_id=channel_identifier, ) if not channel_state: raise RaidenUnrecoverableError( f"Channel was not found before state_change {pex(state_change_identifier)}", ) return channel_state
def channel_state_until_state_change( raiden: 'RaidenService', payment_network_identifier: typing.PaymentNetworkID, token_address: typing.TokenAddress, channel_identifier: typing.ChannelID, state_change_identifier: int, ) -> typing.Optional[NettingChannelState]: """ Go through WAL state changes until a certain balance hash is found. """ # Restore state from the latest snapshot wal = restore_to_state_change( node.state_transition, raiden.wal.storage, state_change_identifier, ) channel_state = views.get_channelstate_by_id( chain_state=wal.state_manager.current_state, payment_network_id=payment_network_identifier, token_address=token_address, channel_id=channel_identifier, ) if not channel_state: raise RaidenUnrecoverableError( f"Channel was not found before state_change {pex(state_change_identifier)}", ) return channel_state
def send_transaction(self, to: Address, startgas: int, value: int = 0, data: bytes = b"") -> TransactionHash: """ Locally sign the transaction and send it to the network. """ with self._sent_lock: if self._sent: raise RaidenUnrecoverableError( f"A transaction for this slot has been sent already! " f"Reusing the nonce is a synchronization problem.") if to == to_canonical_address(NULL_ADDRESS_HEX): warnings.warn( "For contract creation the empty string must be used.") gas_price = self._client.gas_price() transaction = { "data": data, "gas": startgas, "nonce": self.nonce, "value": value, "gasPrice": gas_price, } node_gas_price = self._client.web3.eth.gasPrice log.debug( "Calculated gas price for transaction", node=to_checksum_address(self._client.address), calculated_gas_price=gas_price, node_gas_price=node_gas_price, ) # add the to address if not deploying a contract if to != b"": transaction["to"] = to_checksum_address(to) signed_txn = self._client.web3.eth.account.signTransaction( transaction, self._client.privkey) log_details = { "node": to_checksum_address(self._client.address), "nonce": transaction["nonce"], "gasLimit": transaction["gas"], "gasPrice": transaction["gasPrice"], } log.debug("send_raw_transaction called", **log_details) tx_hash = self._client.web3.eth.sendRawTransaction( signed_txn.rawTransaction) log.debug("send_raw_transaction returned", tx_hash=encode_hex(tx_hash), **log_details) self._sent = True return TransactionHash(tx_hash)
def start_mediated_transfer_with_secret( self, token_network_identifier: TokenNetworkID, amount: TokenAmount, target: TargetAddress, identifier: PaymentID, secret: Secret, ) -> AsyncResult: secret_hash = sha3(secret) if self.default_secret_registry.check_registered(secret_hash): raise RaidenUnrecoverableError( f'Attempted to initiate a locked transfer with secrethash {pex(secret_hash)}.' f' That secret is already registered onchain.', ) self.start_health_check_for(Address(target)) if identifier is None: identifier = create_default_identifier() with self.payment_identifier_lock: payment_status = self.targets_to_identifiers_to_statuses[ target].get(identifier) if payment_status: payment_status_matches = payment_status.matches( token_network_identifier, amount, ) if not payment_status_matches: raise PaymentConflict( 'Another payment with the same id is in flight', ) return payment_status.payment_done payment_status = PaymentStatus( payment_identifier=identifier, amount=amount, token_network_identifier=token_network_identifier, payment_done=AsyncResult(), secret=secret, secret_hash=secret_hash, ) self.targets_to_identifiers_to_statuses[target][ identifier] = payment_status init_initiator_statechange = initiator_init( raiden=self, transfer_identifier=identifier, transfer_amount=amount, transfer_secret=secret, token_network_identifier=token_network_identifier, target_address=target, ) # Dispatch the state change even if there are no routes to create the # wal entry. self.handle_state_change(init_initiator_statechange) return payment_status.payment_done
def update_transfer( self, channel_identifier: typing.ChannelID, partner: typing.Address, balance_hash: typing.BalanceHash, nonce: typing.Nonce, additional_hash: typing.AdditionalHash, closing_signature: typing.Signature, non_closing_signature: typing.Signature, ): log_details = { 'token_network': pex(self.address), 'node': pex(self.node_address), 'partner': pex(partner), 'nonce': nonce, 'balance_hash': encode_hex(balance_hash), 'additional_hash': encode_hex(additional_hash), 'closing_signature': encode_hex(closing_signature), 'non_closing_signature': encode_hex(non_closing_signature), } log.debug('updateNonClosingBalanceProof called', **log_details) self._check_for_outdated_channel( self.node_address, partner, channel_identifier, ) transaction_hash = self.proxy.transact( 'updateNonClosingBalanceProof', channel_identifier, partner, self.node_address, balance_hash, nonce, additional_hash, closing_signature, non_closing_signature, ) self.client.poll(transaction_hash) receipt_or_none = check_transaction_threw(self.client, transaction_hash) if receipt_or_none: channel_closed = self.channel_is_closed( participant1=self.node_address, participant2=partner, channel_identifier=channel_identifier, ) if channel_closed is False: msg = 'Channel is not in a closed state' log.critical(f'updateNonClosingBalanceProof failed, {msg}', **log_details) raise RaidenUnrecoverableError(msg) msg = 'Update NonClosing balance proof' log.critical(f'updateNonClosingBalanceProof failed, {msg}', **log_details) raise TransactionThrew(msg, receipt_or_none) log.info('updateNonClosingBalanceProof successful', **log_details)
def unlock( self, channel_identifier: typing.ChannelID, partner: typing.Address, merkle_tree_leaves: typing.MerkleTreeLeaves, ): log_details = { 'token_network': pex(self.address), 'node': pex(self.node_address), 'partner': pex(partner), 'merkle_tree_leaves': merkle_tree_leaves, } if merkle_tree_leaves is None or not merkle_tree_leaves: log.info('skipping unlock, tree is empty', **log_details) return log.info('unlock called', **log_details) leaves_packed = b''.join(lock.encoded for lock in merkle_tree_leaves) gas_limit = self.proxy.estimate_gas( 'unlock', channel_identifier, self.node_address, partner, leaves_packed, ) gas_limit = safe_gas_limit(gas_limit, UNLOCK_TX_GAS_LIMIT) transaction_hash = self.proxy.transact( 'unlock', gas_limit, channel_identifier, self.node_address, partner, leaves_packed, ) self.client.poll(transaction_hash) receipt_or_none = check_transaction_threw(self.client, transaction_hash) if receipt_or_none: channel_settled = self.channel_is_settled( participant1=self.node_address, participant2=partner, channel_identifier=channel_identifier, ) if channel_settled is False: log.critical('unlock failed. Channel is not in a settled state', **log_details) raise RaidenUnrecoverableError( 'Channel is not in a settled state. An unlock cannot be made', ) log.critical('unlock failed', **log_details) raise TransactionThrew('Unlock', receipt_or_none) log.info('unlock successful', **log_details)
def approve(self, allowed_address: Address, allowance: TokenAmount): """ Aprove `allowed_address` to transfer up to `deposit` amount of token. Note: For channel deposit please use the channel proxy, since it does additional validations. """ log_details = { 'node': pex(self.node_address), 'contract': pex(self.address), 'allowed_address': pex(allowed_address), 'allowance': allowance, } checking_block = self.client.get_checking_block() error_prefix = 'Call to approve will fail' gas_limit = self.proxy.estimate_gas( checking_block, 'approve', to_checksum_address(allowed_address), allowance, ) if gas_limit: error_prefix = 'Call to approve failed' log.debug('approve called', **log_details) transaction_hash = self.proxy.transact( 'approve', safe_gas_limit(gas_limit), to_checksum_address(allowed_address), allowance, ) self.client.poll(transaction_hash) receipt_or_none = check_transaction_threw(self.client, transaction_hash) transaction_executed = gas_limit is not None if not transaction_executed or receipt_or_none: if transaction_executed: block = receipt_or_none['blockNumber'] else: block = checking_block self.proxy.jsonrpc_client.check_for_insufficient_eth( transaction_name='approve', transaction_executed=transaction_executed, required_gas=GAS_REQUIRED_FOR_APPROVE, block_identifier=block, ) msg = self._check_why_approved_failed(allowance, block) error_msg = f'{error_prefix}. {msg}' log.critical(error_msg, **log_details) raise RaidenUnrecoverableError(error_msg) log.info('approve successful', **log_details)
def deposit(self, block_identifier: BlockIdentifier, limit_amount: TokenAmount) -> None: """Makes a deposit to create or extend a registration""" extra_log_details = {"given_block_identifier": block_identifier} estimated_transaction = self.client.estimate_gas( self.proxy, "deposit", extra_log_details, limit_amount) if estimated_transaction is None: msg = "ServiceRegistry.deposit transaction fails" raise RaidenUnrecoverableError(msg) transaction_sent = self.client.transact(estimated_transaction) transaction_mined = self.client.poll_transaction(transaction_sent) if not was_transaction_successfully_mined(transaction_mined): msg = "ServiceRegistry.deposit transaction failed" raise RaidenUnrecoverableError(msg)
def _check_channel_state_for_close(self, participant1, participant2, channel_identifier): channel_state = self._get_channel_state( participant1=participant1, participant2=participant2, channel_identifier=channel_identifier, ) if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED): raise RaidenUnrecoverableError( f'Channel between participant {participant1} ' f'and {participant2} does not exist', ) elif channel_state == ChannelState.SETTLED: raise RaidenUnrecoverableError( 'A settled channel cannot be closed', ) elif channel_state == ChannelState.CLOSED: raise RaidenRecoverableError('Channel is already closed', )
def approve(self, allowed_address: Address, allowance: TokenAmount): """ Aprove `allowed_address` to transfer up to `deposit` amount of token. Note: For channel deposit please use the channel proxy, since it does additional validations. """ # Note that given_block_identifier is not used here as there # are no preconditions to check before sending the transaction log_details = { "node": pex(self.node_address), "contract": pex(self.address), "allowed_address": pex(allowed_address), "allowance": allowance, } checking_block = self.client.get_checking_block() error_prefix = "Call to approve will fail" gas_limit = self.proxy.estimate_gas( checking_block, "approve", to_checksum_address(allowed_address), allowance ) if gas_limit: error_prefix = "Call to approve failed" log.debug("approve called", **log_details) transaction_hash = self.proxy.transact( "approve", safe_gas_limit(gas_limit), to_checksum_address(allowed_address), allowance, ) self.client.poll(transaction_hash) receipt_or_none = check_transaction_threw(self.client, transaction_hash) transaction_executed = gas_limit is not None if not transaction_executed or receipt_or_none: if transaction_executed: block = receipt_or_none["blockNumber"] else: block = checking_block self.proxy.jsonrpc_client.check_for_insufficient_eth( address=self.node_address, transaction_name="approve", transaction_executed=transaction_executed, required_gas=GAS_REQUIRED_FOR_APPROVE, block_identifier=block, ) msg = self._check_why_approved_failed(allowance, block) error_msg = f"{error_prefix}. {msg}" log.critical(error_msg, **log_details) raise RaidenUnrecoverableError(error_msg) log.info("approve successful", **log_details)
def handle_contract_send_secretreveal( raiden: "RaidenService", channel_reveal_secret_event: ContractSendSecretReveal ) -> None: # pragma: no unittest try: raiden.default_secret_registry.register_secret( secret=channel_reveal_secret_event.secret ) except InsufficientEth as e: raise RaidenUnrecoverableError(str(e)) from e
def raise_on_call_returned_empty( given_block_identifier: BlockIdentifier) -> NoReturn: """Format a message and raise RaidenUnrecoverableError.""" # We know that the given address has code because this is checked # in the constructor msg = (f"Either the given address is for a different smart contract, " f"or the contract was not yet deployed at the block " f"{format_block_id(given_block_identifier)}. Either way this call " f"should never have happened.") raise RaidenUnrecoverableError(msg)
def _check_channel_state_for_settle(self, participant1, participant2, channel_identifier): channel_data = self.detail_channel(participant1, participant2, channel_identifier) if channel_data.state == ChannelState.SETTLED: raise RaidenRecoverableError('Channel is already settled', ) elif channel_data.state == ChannelState.REMOVED: raise RaidenRecoverableError( 'Channel is already unlocked. It cannot be settled', ) elif channel_data.state == ChannelState.OPENED: raise RaidenUnrecoverableError( 'Channel is still open. It cannot be settled', ) elif channel_data.state == ChannelState.CLOSED: if self.client.block_number() < channel_data.settle_block_number: raise RaidenUnrecoverableError( 'Channel cannot be settled before settlement window is over', ) raise RaidenRecoverableError( 'Channel cannot be settled before closing', )
def handle_contract_send_channelclose( raiden: "RaidenService", chain_state: ChainState, channel_close_event: ContractSendChannelClose, ) -> None: balance_proof = channel_close_event.balance_proof if balance_proof: nonce = balance_proof.nonce balance_hash = balance_proof.balance_hash signature_in_proof = balance_proof.signature message_hash = balance_proof.message_hash canonical_identifier = balance_proof.canonical_identifier else: nonce = Nonce(0) balance_hash = EMPTY_BALANCE_HASH signature_in_proof = EMPTY_SIGNATURE message_hash = EMPTY_MESSAGE_HASH canonical_identifier = channel_close_event.canonical_identifier closing_data = pack_signed_balance_proof( msg_type=MessageTypeId.BALANCE_PROOF, nonce=nonce, balance_hash=balance_hash, additional_hash=message_hash, canonical_identifier=canonical_identifier, partner_signature=signature_in_proof, ) our_signature = raiden.signer.sign(data=closing_data) confirmed_block_identifier = state_from_raiden(raiden).block_hash channel_state = get_channelstate_by_canonical_identifier( chain_state=chain_state, canonical_identifier=channel_close_event.canonical_identifier) if channel_state is None: raise RaidenUnrecoverableError( "ContractSendChannelClose for inexesting channel.") channel_proxy = raiden.proxy_manager.payment_channel( channel_state=channel_state, block_identifier=confirmed_block_identifier) channel_proxy.close( nonce=nonce, balance_hash=balance_hash, additional_hash=message_hash, non_closing_signature=signature_in_proof, closing_signature=our_signature, block_identifier=channel_close_event.triggered_by_block_hash, )
def raise_on_call_returned_empty( given_block_identifier: BlockSpecification) -> NoReturn: """Format a message and raise RaidenUnrecoverableError.""" # We know that the given address has code because this is checked # in the constructor if isinstance(given_block_identifier, T_BlockHash): given_block_identifier = to_hex(given_block_identifier) msg = (f"Either the given address is for a different smart contract, " f"or the contract was not yet deployed at the block " f"{given_block_identifier}. Either way this call should never " f"happened.") raise RaidenUnrecoverableError(msg)
def transact( self, function_name: str, startgas: int, *args: Any, **kwargs: Any ) -> TransactionHash: data = ContractProxy.get_transaction_data( abi=self.contract.abi, function_name=function_name, args=args, kwargs=kwargs ) slot = self.rpc_client.get_next_transaction() try: tx_hash = slot.send_transaction( to=self.contract.address, startgas=startgas, value=kwargs.pop("value", 0), data=decode_hex(data), ) except ValueError as e: action = inspect_client_error(e, self.rpc_client.eth_node) if action == ClientErrorInspectResult.INSUFFICIENT_FUNDS: raise InsufficientEth( "Transaction failed due to insufficient ETH balance. " "Please top up your ETH account." ) elif action == ClientErrorInspectResult.TRANSACTION_UNDERPRICED: raise ReplacementTransactionUnderpriced( "Transaction was rejected. This is potentially " "caused by the reuse of the previous transaction " "nonce as well as paying an amount of gas less than or " "equal to the previous transaction's gas amount" ) elif action in THE_NONCE_WAS_REUSED: # XXX: Add logic to check that it is the same transaction # (instead of relying on the error message), and instead of # raising an unrecoverable error proceed as normal with the # polling. # # This was previously done, but removed by #4909, and for it to # be finished #2088 has to be implemented. raise EthereumNonceTooLow( "Transaction rejected because the nonce has been already mined." ) raise RaidenUnrecoverableError( f"Unexpected error in underlying Ethereum node: {str(e)}" ) return tx_hash
def join_broadcast_room(client: GMatrixClient, broadcast_room_alias: str) -> Room: """ Join the public broadcast through the alias `broadcast_room_alias`. When a new Matrix instance is deployed the broadcast room _must_ be created and aliased, Raiden will not use a server that does not have the discovery room properly set. Requiring the setup of the broadcast alias as part of the server setup fixes a serious race condition where multiple discovery rooms are created, which would break the presence checking. See: https://github.com/raiden-network/raiden-transport/issues/46 """ try: return client.join_room(broadcast_room_alias) except MatrixRequestError: raise RaidenUnrecoverableError( f"Could not join broadcast room {broadcast_room_alias}. " f"Make sure the Matrix server you're trying to connect to uses the recommended server " f"setup, esp. the server-side broadcast room creation. " f"See https://github.com/raiden-network/raiden-transport.")
def kill_offender(hub: Hub) -> None: if greenlet_tracer.did_block_hub(hub): active_greenlet = greenlet_tracer.active_greenlet msg = "" if monitor_thread._tracer.active_greenlet != active_greenlet: msg = ( f"Mismatch values for the active_greenlet among the " f"monitor_thread and deubgging tracer, this either means " f"there is a bug in the trace chain (the wrong values are " f"forwarded), or that one of the trace functions was wrongly " f"uninstalled. Active greenlets " f"monitor_thread={monitor_thread._tracer.active_greenlet} " f"debug_tracer={active_greenlet}.") hub.loop.run_callback(lambda: active_greenlet.throw( RaidenUnrecoverableError( f"A greenlet used the CPU for longer than " f"{gevent.config.max_blocking_time} seconds, killing it.{msg}" )))
def test_run_error_reporting(cli_runner, monkeypatch): caught_exceptions = { APIServerPortInUseError(): ReturnCode.PORT_ALREADY_IN_USE, ConfigurationError(): ReturnCode.RAIDEN_CONFIGURATION_ERROR, ConnectTimeout(): ReturnCode.GENERIC_COMMUNICATION_ERROR, ConnectionError(): ReturnCode.GENERIC_COMMUNICATION_ERROR, EthereumNonceTooLow(): ReturnCode.ETH_ACCOUNT_ERROR, EthNodeInterfaceError(): ReturnCode.ETH_INTERFACE_ERROR, KeystoreAuthenticationError(): ReturnCode.ETH_ACCOUNT_ERROR, KeystoreFileNotFound(): ReturnCode.ETH_ACCOUNT_ERROR, RaidenUnrecoverableError(): ReturnCode.FATAL, ReplacementTransactionUnderpriced(): ReturnCode.ETH_ACCOUNT_ERROR, RequestsConnectionError(): ReturnCode.GENERIC_COMMUNICATION_ERROR, Exception(): ReturnCode.FATAL, } for exception, code in caught_exceptions.items(): monkeypatch.setattr(cli, "run_services", mock_raises(exception)) result = cli_runner(cli.run, "--accept-disclaimer") assert result.exception.code == code