/**
  * Closes the connection by generating a settle message for the client and calls {@link
  * ServerConnection#destroyConnection(CloseReason)}. Note that this does not broadcast the payment
  * transaction and the client may still resume the same channel if they reconnect
  *
  * <p>
  *
  * <p>Note that {@link PaymentChannelServer#connectionClosed()} must still be called after the
  * connection fully closes.
  */
 public void close() {
   lock.lock();
   try {
     if (connectionOpen && !channelSettling) {
       final Protos.TwoWayChannelMessage.Builder msg = Protos.TwoWayChannelMessage.newBuilder();
       msg.setType(Protos.TwoWayChannelMessage.MessageType.CLOSE);
       conn.sendToClient(msg.build());
       conn.destroyConnection(CloseReason.SERVER_REQUESTED_CLOSE);
     }
   } finally {
     lock.unlock();
   }
 }
  @GuardedBy("lock")
  private void receiveUpdatePaymentMessage(Protos.UpdatePayment msg, boolean sendAck)
      throws VerificationException, ValueOutOfRangeException, InsufficientMoneyException {
    log.info("Got a payment update");

    Coin lastBestPayment = state.getBestValueToMe();
    final Coin refundSize = Coin.valueOf(msg.getClientChangeValue());
    boolean stillUsable = state.incrementPayment(refundSize, msg.getSignature().toByteArray());
    Coin bestPaymentChange = state.getBestValueToMe().subtract(lastBestPayment);

    ListenableFuture<ByteString> ackInfoFuture = null;
    if (bestPaymentChange.signum() > 0) {
      ByteString info = (msg.hasInfo()) ? msg.getInfo() : null;
      ackInfoFuture = conn.paymentIncrease(bestPaymentChange, state.getBestValueToMe(), info);
    }

    if (sendAck) {
      final Protos.TwoWayChannelMessage.Builder ack = Protos.TwoWayChannelMessage.newBuilder();
      ack.setType(Protos.TwoWayChannelMessage.MessageType.PAYMENT_ACK);
      if (ackInfoFuture == null) {
        conn.sendToClient(ack.build());
      } else {
        Futures.addCallback(
            ackInfoFuture,
            new FutureCallback<ByteString>() {
              @Override
              public void onSuccess(@Nullable ByteString result) {
                if (result != null) ack.setPaymentAck(ack.getPaymentAckBuilder().setInfo(result));
                conn.sendToClient(ack.build());
              }

              @Override
              public void onFailure(Throwable t) {
                log.info("Failed retrieving paymentIncrease info future");
                error(
                    "Failed processing payment update",
                    Protos.Error.ErrorCode.OTHER,
                    CloseReason.UPDATE_PAYMENT_FAILED);
              }
            });
      }
    }

    if (!stillUsable) {
      log.info("Channel is now fully exhausted, closing/initiating settlement");
      settlePayment(CloseReason.CHANNEL_EXHAUSTED);
    }
  }