private Wallet restoreWalletFromBackup() {
    InputStream is = null;

    try {
      is = openFileInput(Constants.Files.WALLET_KEY_BACKUP_PROTOBUF);

      final Wallet wallet = new WalletProtobufSerializer().readWallet(is);

      if (!wallet.isConsistent()) throw new Error("inconsistent backup");

      resetBlockchain();

      Toast.makeText(this, R.string.toast_wallet_reset, Toast.LENGTH_LONG).show();

      log.info("wallet restored from backup: '" + Constants.Files.WALLET_KEY_BACKUP_PROTOBUF + "'");

      return wallet;
    } catch (final IOException x) {
      throw new Error("cannot read backup", x);
    } catch (final UnreadableWalletException x) {
      throw new Error("cannot read backup", x);
    } finally {
      try {
        is.close();
      } catch (final IOException x) {
        // swallow
      }
    }
  }
  private void afterLoadWallet() {
    wallet.autosaveToFile(walletFile, 10, TimeUnit.SECONDS, new WalletAutosaveEventListener());

    // clean up spam
    wallet.cleanup();

    migrateBackup();
  }
  public void replaceWallet(final Wallet newWallet) {

    internalResetBlockchain(); // implicitly stops blockchain service
    wallet.shutdownAutosaveAndWait();

    wallet = newWallet;
    config.maybeIncrementBestChainHeightEver(newWallet.getLastBlockSeenHeight());
    afterLoadWallet();

    final Intent broadcast = new Intent(ACTION_WALLET_CHANGED);
    broadcast.setPackage(getPackageName());
    LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);

    config.disarmBackupReminder();
  }
  /**
   * Called when the connection terminates. Notifies the {@link StoredServerChannel} object that we
   * can attempt to resume this channel in the future and stops generating messages for the client.
   *
   * <p>Note that this <b>MUST</b> still be called even after either {@link
   * ServerConnection#destroyConnection(CloseReason)} or {@link PaymentChannelServer#close()} is
   * called to actually handle the connection close logic.
   */
  public void connectionClosed() {
    lock.lock();
    try {
      log.info("Server channel closed.");
      connectionOpen = false;

      try {
        if (state != null && state.getMultisigContract() != null) {
          StoredPaymentChannelServerStates channels =
              (StoredPaymentChannelServerStates)
                  wallet.getExtensions().get(StoredPaymentChannelServerStates.EXTENSION_ID);
          if (channels != null) {
            StoredServerChannel storedServerChannel =
                channels.getChannel(state.getMultisigContract().getHash());
            if (storedServerChannel != null) {
              storedServerChannel.clearConnectedHandler();
            }
          }
        }
      } catch (IllegalStateException e) {
        // Expected when we call getMultisigContract() sometimes
      }
    } finally {
      lock.unlock();
    }
  }
  private void protobufSerializeWallet(@Nonnull final Wallet wallet) throws IOException {
    final long start = System.currentTimeMillis();

    wallet.saveToFile(walletFile);

    // make wallets world accessible in test mode
    if (Constants.TEST) Io.chmod(walletFile, 0777);

    log.debug(
        "wallet saved to: '"
            + walletFile
            + "', took "
            + (System.currentTimeMillis() - start)
            + "ms");
  }
  @GuardedBy("lock")
  private void receiveContractMessage(Protos.TwoWayChannelMessage msg)
      throws VerificationException {
    checkState(step == InitStep.WAITING_ON_CONTRACT && msg.hasProvideContract());
    log.info("Got contract, broadcasting and responding with CHANNEL_OPEN");
    final Protos.ProvideContract providedContract = msg.getProvideContract();

    // TODO notify connection handler that timeout should be significantly extended as we wait for
    // network propagation?
    final Transaction multisigContract =
        new Transaction(wallet.getParams(), providedContract.getTx().toByteArray());
    step = InitStep.WAITING_ON_MULTISIG_ACCEPTANCE;
    state
        .provideMultiSigContract(multisigContract)
        .addListener(
            new Runnable() {
              @Override
              public void run() {
                multisigContractPropogated(providedContract, multisigContract.getHash());
              }
            },
            Threading.SAME_THREAD);
  }
  @GuardedBy("lock")
  private void receiveRefundMessage(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(step == InitStep.WAITING_ON_UNSIGNED_REFUND && msg.hasProvideRefund());
    log.info("Got refund transaction, returning signature");

    Protos.ProvideRefund providedRefund = msg.getProvideRefund();
    state = new PaymentChannelServerState(broadcaster, wallet, myKey, expireTime);
    byte[] signature =
        state.provideRefundTransaction(
            new Transaction(wallet.getParams(), providedRefund.getTx().toByteArray()),
            providedRefund.getMultisigKey().toByteArray());

    step = InitStep.WAITING_ON_CONTRACT;

    Protos.ReturnRefund.Builder returnRefundBuilder =
        Protos.ReturnRefund.newBuilder().setSignature(ByteString.copyFrom(signature));

    conn.sendToClient(
        Protos.TwoWayChannelMessage.newBuilder()
            .setReturnRefund(returnRefundBuilder)
            .setType(Protos.TwoWayChannelMessage.MessageType.RETURN_REFUND)
            .build());
  }
 public void processDirectTransaction(@Nonnull final Transaction tx) throws VerificationException {
   if (wallet.isTransactionRelevant(tx)) {
     wallet.receivePending(tx, null);
     broadcastTransaction(tx);
   }
 }
  private void loadWalletFromProtobuf() {
    if (walletFile.exists()) {
      final long start = System.currentTimeMillis();

      FileInputStream walletStream = null;

      try {
        walletStream = new FileInputStream(walletFile);

        wallet = new WalletProtobufSerializer().readWallet(walletStream);

        if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
          throw new UnreadableWalletException(
              "bad wallet network parameters: " + wallet.getParams().getId());

        log.info(
            "wallet loaded from: '"
                + walletFile
                + "', took "
                + (System.currentTimeMillis() - start)
                + "ms");
      } catch (final FileNotFoundException x) {
        log.error("problem loading wallet", x);

        Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();

        wallet = restoreWalletFromBackup();
      } catch (final UnreadableWalletException x) {
        log.error("problem loading wallet", x);

        Toast.makeText(WalletApplication.this, x.getClass().getName(), Toast.LENGTH_LONG).show();

        wallet = restoreWalletFromBackup();
      } finally {
        if (walletStream != null) {
          try {
            walletStream.close();
          } catch (final IOException x) {
            // swallow
          }
        }
      }

      if (!wallet.isConsistent()) {
        Toast.makeText(this, "inconsistent wallet: " + walletFile, Toast.LENGTH_LONG).show();

        wallet = restoreWalletFromBackup();
      }

      if (!wallet.getParams().equals(Constants.NETWORK_PARAMETERS))
        throw new Error("bad wallet network parameters: " + wallet.getParams().getId());
    } else {
      wallet = new Wallet(Constants.NETWORK_PARAMETERS);

      backupWallet();

      config.armBackupReminder();

      log.info("new wallet created");
    }
  }
  @GuardedBy("lock")
  private void receiveVersionMessage(Protos.TwoWayChannelMessage msg) throws VerificationException {
    checkState(step == InitStep.WAITING_ON_CLIENT_VERSION && msg.hasClientVersion());
    final Protos.ClientVersion clientVersion = msg.getClientVersion();
    final int major = clientVersion.getMajor();
    if (major != SERVER_MAJOR_VERSION) {
      error(
          "This server needs protocol version "
              + SERVER_MAJOR_VERSION
              + " , client offered "
              + major,
          Protos.Error.ErrorCode.NO_ACCEPTABLE_VERSION,
          CloseReason.NO_ACCEPTABLE_VERSION);
      return;
    }

    Protos.ServerVersion.Builder versionNegotiationBuilder =
        Protos.ServerVersion.newBuilder()
            .setMajor(SERVER_MAJOR_VERSION)
            .setMinor(SERVER_MINOR_VERSION);
    conn.sendToClient(
        Protos.TwoWayChannelMessage.newBuilder()
            .setType(Protos.TwoWayChannelMessage.MessageType.SERVER_VERSION)
            .setServerVersion(versionNegotiationBuilder)
            .build());
    ByteString reopenChannelContractHash = clientVersion.getPreviousChannelContractHash();
    if (reopenChannelContractHash != null && reopenChannelContractHash.size() == 32) {
      Sha256Hash contractHash = new Sha256Hash(reopenChannelContractHash.toByteArray());
      log.info("New client that wants to resume {}", contractHash);
      StoredPaymentChannelServerStates channels =
          (StoredPaymentChannelServerStates)
              wallet.getExtensions().get(StoredPaymentChannelServerStates.EXTENSION_ID);
      if (channels != null) {
        StoredServerChannel storedServerChannel = channels.getChannel(contractHash);
        if (storedServerChannel != null) {
          final PaymentChannelServer existingHandler =
              storedServerChannel.setConnectedHandler(this, false);
          if (existingHandler != this) {
            log.warn("  ... and that channel is already in use, disconnecting other user.");
            existingHandler.close();
            storedServerChannel.setConnectedHandler(this, true);
          }

          log.info("Got resume version message, responding with VERSIONS and CHANNEL_OPEN");
          state = storedServerChannel.getOrCreateState(wallet, broadcaster);
          step = InitStep.CHANNEL_OPEN;
          conn.sendToClient(
              Protos.TwoWayChannelMessage.newBuilder()
                  .setType(Protos.TwoWayChannelMessage.MessageType.CHANNEL_OPEN)
                  .build());
          conn.channelOpen(contractHash);
          return;
        } else {
          log.error(" ... but we do not have any record of that contract! Resume failed.");
        }
      } else {
        log.error(" ... but we do not have any stored channels! Resume failed.");
      }
    }
    log.info(
        "Got initial version message, responding with VERSIONS and INITIATE: min value={}",
        minAcceptedChannelSize.value);

    myKey = new ECKey();
    wallet.freshReceiveKey();

    expireTime = Utils.currentTimeSeconds() + truncateTimeWindow(clientVersion.getTimeWindowSecs());
    step = InitStep.WAITING_ON_UNSIGNED_REFUND;

    Protos.Initiate.Builder initiateBuilder =
        Protos.Initiate.newBuilder()
            .setMultisigKey(ByteString.copyFrom(myKey.getPubKey()))
            .setExpireTimeSecs(expireTime)
            .setMinAcceptedChannelSize(minAcceptedChannelSize.value)
            .setMinPayment(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.value);

    conn.sendToClient(
        Protos.TwoWayChannelMessage.newBuilder()
            .setInitiate(initiateBuilder)
            .setType(Protos.TwoWayChannelMessage.MessageType.INITIATE)
            .build());
  }