<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def close( self, channel_identifier: ChannelID, partner: Address, balance_hash: BalanceHash, nonce: Nonce, additional_hash: AdditionalHash, signature: Signature, given_block_identifier: BlockSpecification, ):
 """ Close the channel using the provided balance proof. Note: This method must *not* be called without updating the application state, otherwise the node may accept new transfers which cannot be used, because the closer is not allowed to update the balance proof submitted on chain after closing Raises: RaidenRecoverableError: If the channel is already closed. RaidenUnrecoverableError: If the channel does not exist or is settled. """


        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),
            'signature': encode_hex(signature),
        }
        log.debug('closeChannel called', **log_details)

        checking_block = self.client.get_checking_block()
        try:
            self._close_preconditions(
                channel_identifier,
                partner=partner,
                block_identifier=given_block_identifier,
            )
        except NoStateForBlockIdentifier:
            # If preconditions end up being on pruned state skip them. Estimate
            # gas will stop us from sending a transaction that will fail
            pass

        error_prefix = 'closeChannel call will fail'
        with self.channel_operations_lock[partner]:
            gas_limit = self.proxy.estimate_gas(
                checking_block,
                'closeChannel',
                channel_identifier=channel_identifier,
                partner=partner,
                balance_hash=balance_hash,
                nonce=nonce,
                additional_hash=additional_hash,
                signature=signature,
            )

            if gas_limit:
                error_prefix = 'closeChannel call failed'
                transaction_hash = self.proxy.transact(
                    'closeChannel',
                    safe_gas_limit(gas_limit, GAS_REQUIRED_FOR_CLOSE_CHANNEL),
                    channel_identifier=channel_identifier,
                    partner=partner,
                    balance_hash=balance_hash,
                    nonce=nonce,
                    additional_hash=additional_hash,
                    signature=signature,
                )
                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='closeChannel',
                    transaction_executed=transaction_executed,
                    required_gas=GAS_REQUIRED_FOR_CLOSE_CHANNEL,
                    block_identifier=block,
                )
                error_type, msg = self._check_channel_state_for_close(
                    participant1=self.node_address,
                    participant2=partner,
                    block_identifier=block,
                    channel_identifier=channel_identifier,
                )
                if not error_type:
                    # error_type can also be None above in which case it's
                    # unknown reason why we would fail.
                    error_type = RaidenUnrecoverableError
                error_msg = f'{error_prefix}. {msg}'
                if error_type == RaidenRecoverableError:
                    log.warning(error_msg, **log_details)
                else:
                    log.critical(error_msg, **log_details)

                raise error_type(error_msg)

        log.info('closeChannel successful', **log_details)