@GuardedBy("lock")
 private void receiveCloseMessage() throws InsufficientMoneyException {
   log.info("Got CLOSE message, closing channel");
   if (state != null) {
     settlePayment(CloseReason.CLIENT_REQUESTED_CLOSE);
   } else {
     conn.destroyConnection(CloseReason.CLIENT_REQUESTED_CLOSE);
   }
 }
 private void error(String message, Protos.Error.ErrorCode errorCode, CloseReason closeReason) {
   log.error(message);
   Protos.Error.Builder errorBuilder;
   errorBuilder = Protos.Error.newBuilder().setCode(errorCode).setExplanation(message);
   conn.sendToClient(
       Protos.TwoWayChannelMessage.newBuilder()
           .setError(errorBuilder)
           .setType(Protos.TwoWayChannelMessage.MessageType.ERROR)
           .build());
   conn.destroyConnection(closeReason);
 }
 /**
  * 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();
   }
 }
 /**
  * Called when a message is received from the client. Processes the given message and generates
  * events based on its content.
  */
 public void receiveMessage(Protos.TwoWayChannelMessage msg) {
   lock.lock();
   try {
     checkState(connectionOpen);
     if (channelSettling) return;
     // If we generate an error, we set errorBuilder and closeReason and break, otherwise we return
     Protos.Error.Builder errorBuilder;
     CloseReason closeReason;
     try {
       switch (msg.getType()) {
         case CLIENT_VERSION:
           receiveVersionMessage(msg);
           return;
         case PROVIDE_REFUND:
           receiveRefundMessage(msg);
           return;
         case PROVIDE_CONTRACT:
           receiveContractMessage(msg);
           return;
         case UPDATE_PAYMENT:
           checkState(step == InitStep.CHANNEL_OPEN && msg.hasUpdatePayment());
           receiveUpdatePaymentMessage(msg.getUpdatePayment(), true);
           return;
         case CLOSE:
           receiveCloseMessage();
           return;
         case ERROR:
           checkState(msg.hasError());
           log.error(
               "Client sent ERROR {} with explanation {}",
               msg.getError().getCode().name(),
               msg.getError().hasExplanation() ? msg.getError().getExplanation() : "");
           conn.destroyConnection(CloseReason.REMOTE_SENT_ERROR);
           return;
         default:
           final String errorText =
               "Got unknown message type or type that doesn't apply to servers.";
           error(
               errorText,
               Protos.Error.ErrorCode.SYNTAX_ERROR,
               CloseReason.REMOTE_SENT_INVALID_MESSAGE);
       }
     } catch (VerificationException e) {
       log.error("Caught verification exception handling message from client", e);
       error(
           e.getMessage(),
           Protos.Error.ErrorCode.BAD_TRANSACTION,
           CloseReason.REMOTE_SENT_INVALID_MESSAGE);
     } catch (ValueOutOfRangeException e) {
       log.error("Caught value out of range exception handling message from client", e);
       error(
           e.getMessage(),
           Protos.Error.ErrorCode.BAD_TRANSACTION,
           CloseReason.REMOTE_SENT_INVALID_MESSAGE);
     } catch (InsufficientMoneyException e) {
       log.error("Caught insufficient money exception handling message from client", e);
       error(
           e.getMessage(),
           Protos.Error.ErrorCode.BAD_TRANSACTION,
           CloseReason.REMOTE_SENT_INVALID_MESSAGE);
     } catch (IllegalStateException e) {
       log.error("Caught illegal state exception handling message from client", e);
       error(
           e.getMessage(),
           Protos.Error.ErrorCode.SYNTAX_ERROR,
           CloseReason.REMOTE_SENT_INVALID_MESSAGE);
     }
   } finally {
     lock.unlock();
   }
 }