/** Finds an inactive channel with the given id and returns it, or returns null. */
 @Nullable
 StoredClientChannel getUsableChannelForServerID(Sha256Hash id) {
   lock.lock();
   try {
     Set<StoredClientChannel> setChannels = mapChannels.get(id);
     for (StoredClientChannel channel : setChannels) {
       synchronized (channel) {
         // Check if the channel is usable (has money, inactive) and if so, activate it.
         log.info(
             "Considering channel {} contract {}", channel.hashCode(), channel.contract.getHash());
         if (channel.close != null || channel.valueToMe.equals(Coin.ZERO)) {
           log.info("  ... but is closed or empty");
           continue;
         }
         if (!channel.active) {
           log.info("  ... activating");
           channel.active = true;
           return channel;
         }
         log.info("  ... but is already active");
       }
     }
   } finally {
     lock.unlock();
   }
   return null;
 }
 /**
  * Returns the number of seconds from now until this servers next channel will expire, or zero if
  * no unexpired channels found.
  */
 public long getSecondsUntilExpiry(Sha256Hash id) {
   lock.lock();
   try {
     final Set<StoredClientChannel> setChannels = mapChannels.get(id);
     final long nowSeconds = Utils.currentTimeSeconds();
     int earliestTime = Integer.MAX_VALUE;
     for (StoredClientChannel channel : setChannels) {
       synchronized (channel) {
         if (channel.expiryTimeSeconds() > nowSeconds)
           earliestTime = Math.min(earliestTime, (int) channel.expiryTimeSeconds());
       }
     }
     return earliestTime == Integer.MAX_VALUE ? 0 : earliestTime - nowSeconds;
   } finally {
     lock.unlock();
   }
 }
 @Override
 public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception {
   lock.lock();
   try {
     checkState(this.containingWallet == null || this.containingWallet == containingWallet);
     this.containingWallet = containingWallet;
     NetworkParameters params = containingWallet.getParams();
     ClientState.StoredClientPaymentChannels states =
         ClientState.StoredClientPaymentChannels.parseFrom(data);
     for (ClientState.StoredClientPaymentChannel storedState : states.getChannelsList()) {
       Transaction refundTransaction =
           params
               .getDefaultSerializer()
               .makeTransaction(storedState.getRefundTransaction().toByteArray());
       refundTransaction.getConfidence().setSource(TransactionConfidence.Source.SELF);
       ECKey myKey =
           (storedState.getMyKey().isEmpty())
               ? containingWallet.findKeyFromPubKey(storedState.getMyPublicKey().toByteArray())
               : ECKey.fromPrivate(storedState.getMyKey().toByteArray());
       StoredClientChannel channel =
           new StoredClientChannel(
               Sha256Hash.wrap(storedState.getId().toByteArray()),
               params
                   .getDefaultSerializer()
                   .makeTransaction(storedState.getContractTransaction().toByteArray()),
               refundTransaction,
               myKey,
               Coin.valueOf(storedState.getValueToMe()),
               Coin.valueOf(storedState.getRefundFees()),
               false);
       if (storedState.hasCloseTransactionHash()) {
         Sha256Hash closeTxHash =
             Sha256Hash.wrap(storedState.getCloseTransactionHash().toByteArray());
         channel.close = containingWallet.getTransaction(closeTxHash);
       }
       putChannel(channel, false);
     }
   } finally {
     lock.unlock();
   }
 }
 // Adds this channel and optionally notifies the wallet of an update to this extension (used
 // during deserialize)
 private void putChannel(final StoredClientChannel channel, boolean updateWallet) {
   lock.lock();
   try {
     mapChannels.put(channel.id, channel);
     channelTimeoutHandler.schedule(
         new TimerTask() {
           @Override
           public void run() {
             TransactionBroadcaster announcePeerGroup = getAnnouncePeerGroup();
             removeChannel(channel);
             announcePeerGroup.broadcastTransaction(channel.contract);
             announcePeerGroup.broadcastTransaction(channel.refund);
           }
           // Add the difference between real time and Utils.now() so that test-cases can use a
           // mock clock.
         },
         new Date(
             channel.expiryTimeSeconds() * 1000
                 + (System.currentTimeMillis() - Utils.currentTimeMillis())));
   } finally {
     lock.unlock();
   }
   if (updateWallet) updatedChannel(channel);
 }
 /**
  * Notifies the set of stored states that a channel has been updated. Use to notify the wallet of
  * an update to this wallet extension.
  */
 void updatedChannel(final StoredClientChannel channel) {
   log.info("Stored client channel {} was updated", channel.hashCode());
   containingWallet.addOrUpdateExtension(this);
 }