private WalletTransaction connectTransactionOutputs(
      org.bitcoinj.wallet.Protos.Transaction txProto) throws UnreadableWalletException {
    Transaction tx = txMap.get(txProto.getHash());
    final WalletTransaction.Pool pool;
    switch (txProto.getPool()) {
      case DEAD:
        pool = WalletTransaction.Pool.DEAD;
        break;
      case PENDING:
        pool = WalletTransaction.Pool.PENDING;
        break;
      case SPENT:
        pool = WalletTransaction.Pool.SPENT;
        break;
      case UNSPENT:
        pool = WalletTransaction.Pool.UNSPENT;
        break;
        // Upgrade old wallets: inactive pool has been merged with the pending pool.
        // Remove this some time after 0.9 is old and everyone has upgraded.
        // There should not be any spent outputs in this tx as old wallets would not allow them to
        // be spent
        // in this state.
      case INACTIVE:
      case PENDING_INACTIVE:
        pool = WalletTransaction.Pool.PENDING;
        break;
      default:
        throw new UnreadableWalletException("Unknown transaction pool: " + txProto.getPool());
    }
    for (int i = 0; i < tx.getOutputs().size(); i++) {
      TransactionOutput output = tx.getOutputs().get(i);
      final Protos.TransactionOutput transactionOutput = txProto.getTransactionOutput(i);
      if (transactionOutput.hasSpentByTransactionHash()) {
        final ByteString spentByTransactionHash = transactionOutput.getSpentByTransactionHash();
        Transaction spendingTx = txMap.get(spentByTransactionHash);
        if (spendingTx == null) {
          throw new UnreadableWalletException(
              String.format(
                  "Could not connect %s to %s",
                  tx.getHashAsString(), byteStringToHash(spentByTransactionHash)));
        }
        final int spendingIndex = transactionOutput.getSpentByTransactionIndex();
        TransactionInput input = checkNotNull(spendingTx.getInput(spendingIndex));
        input.connect(output);
      }
    }

    if (txProto.hasConfidence()) {
      Protos.TransactionConfidence confidenceProto = txProto.getConfidence();
      TransactionConfidence confidence = tx.getConfidence();
      readConfidence(tx, confidenceProto, confidence);
    }

    return new WalletTransaction(pool, tx);
  }
 private void loadExtensions(
     Wallet wallet, WalletExtension[] extensionsList, Protos.Wallet walletProto)
     throws UnreadableWalletException {
   final Map<String, WalletExtension> extensions = new HashMap<String, WalletExtension>();
   for (WalletExtension e : extensionsList) extensions.put(e.getWalletExtensionID(), e);
   // The Wallet object, if subclassed, might have added some extensions to itself already. In that
   // case, don't
   // expect them to be passed in, just fetch them here and don't re-add.
   extensions.putAll(wallet.getExtensions());
   for (Protos.Extension extProto : walletProto.getExtensionList()) {
     String id = extProto.getId();
     WalletExtension extension = extensions.get(id);
     if (extension == null) {
       if (extProto.getMandatory()) {
         if (requireMandatoryExtensions)
           throw new UnreadableWalletException("Unknown mandatory extension in wallet: " + id);
         else log.error("Unknown extension in wallet {}, ignoring", id);
       }
     } else {
       log.info("Loading wallet extension {}", id);
       try {
         extension.deserializeWalletExtension(wallet, extProto.getData().toByteArray());
         wallet.addOrGetExistingExtension(extension);
       } catch (Exception e) {
         if (extProto.getMandatory() && requireMandatoryExtensions)
           throw new UnreadableWalletException(
               "Could not parse mandatory extension in wallet: " + id);
         else log.error("Error whilst reading extension {}, ignoring", id, e);
       }
     }
   }
 }
 private void readConfidence(
     Transaction tx,
     Protos.TransactionConfidence confidenceProto,
     TransactionConfidence confidence)
     throws UnreadableWalletException {
   // We are lenient here because tx confidence is not an essential part of the wallet.
   // If the tx has an unknown type of confidence, ignore.
   if (!confidenceProto.hasType()) {
     log.warn("Unknown confidence type for tx {}", tx.getHashAsString());
     return;
   }
   ConfidenceType confidenceType;
   switch (confidenceProto.getType()) {
     case BUILDING:
       confidenceType = ConfidenceType.BUILDING;
       break;
     case DEAD:
       confidenceType = ConfidenceType.DEAD;
       break;
       // These two are equivalent (must be able to read old wallets).
     case NOT_IN_BEST_CHAIN:
       confidenceType = ConfidenceType.PENDING;
       break;
     case PENDING:
       confidenceType = ConfidenceType.PENDING;
       break;
     case UNKNOWN:
       // Fall through.
     default:
       confidenceType = ConfidenceType.UNKNOWN;
       break;
   }
   confidence.setConfidenceType(confidenceType);
   if (confidenceProto.hasAppearedAtHeight()) {
     if (confidence.getConfidenceType() != ConfidenceType.BUILDING) {
       log.warn("Have appearedAtHeight but not BUILDING for tx {}", tx.getHashAsString());
       return;
     }
     confidence.setAppearedAtChainHeight(confidenceProto.getAppearedAtHeight());
   }
   if (confidenceProto.hasDepth()) {
     if (confidence.getConfidenceType() != ConfidenceType.BUILDING) {
       log.warn("Have depth but not BUILDING for tx {}", tx.getHashAsString());
       return;
     }
     confidence.setDepthInBlocks(confidenceProto.getDepth());
   }
   if (confidenceProto.hasOverridingTransaction()) {
     if (confidence.getConfidenceType() != ConfidenceType.DEAD) {
       log.warn("Have overridingTransaction but not OVERRIDDEN for tx {}", tx.getHashAsString());
       return;
     }
     Transaction overridingTransaction = txMap.get(confidenceProto.getOverridingTransaction());
     if (overridingTransaction == null) {
       log.warn(
           "Have overridingTransaction that is not in wallet for tx {}", tx.getHashAsString());
       return;
     }
     confidence.setOverridingTransaction(overridingTransaction);
   }
   for (Protos.PeerAddress proto : confidenceProto.getBroadcastByList()) {
     InetAddress ip;
     try {
       ip = InetAddress.getByAddress(proto.getIpAddress().toByteArray());
     } catch (UnknownHostException e) {
       throw new UnreadableWalletException("Peer IP address does not have the right length", e);
     }
     int port = proto.getPort();
     int protocolVersion = tx.getParams().getProtocolVersion();
     PeerAddress address = new PeerAddress(ip, port, protocolVersion);
     address.setServices(BigInteger.valueOf(proto.getServices()));
     confidence.markBroadcastBy(address);
   }
   switch (confidenceProto.getSource()) {
     case SOURCE_SELF:
       confidence.setSource(TransactionConfidence.Source.SELF);
       break;
     case SOURCE_NETWORK:
       confidence.setSource(TransactionConfidence.Source.NETWORK);
       break;
     case SOURCE_UNKNOWN:
       // Fall through.
     default:
       confidence.setSource(TransactionConfidence.Source.UNKNOWN);
       break;
   }
 }