@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 =
           new Transaction(params, storedState.getRefundTransaction().toByteArray());
       refundTransaction.getConfidence().setSource(TransactionConfidence.Source.SELF);
       StoredClientChannel channel =
           new StoredClientChannel(
               new Sha256Hash(storedState.getId().toByteArray()),
               new Transaction(params, storedState.getContractTransaction().toByteArray()),
               refundTransaction,
               new ECKey(new BigInteger(1, storedState.getMyKey().toByteArray()), null, true),
               BigInteger.valueOf(storedState.getValueToMe()),
               BigInteger.valueOf(storedState.getRefundFees()),
               false);
       if (storedState.hasCloseTransactionHash())
         channel.close =
             containingWallet.getTransaction(new Sha256Hash(storedState.toByteArray()));
       putChannel(channel, false);
     }
   } finally {
     lock.unlock();
   }
 }
示例#2
0
  private void loadWalletFromProtobuf() {
    if (walletFile.exists()) {
      final long start = System.currentTimeMillis();

      FileInputStream walletStream = null;

      try {
        walletStream = new FileInputStream(walletFile);

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

        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);

      log.info("new wallet created");
    }

    // this check is needed so encrypted wallets won't get their private keys removed accidently
    for (final ECKey key : wallet.getKeys())
      if (key.getPrivKeyBytes() == null)
        throw new Error(
            "found read-only key, but wallet is likely an encrypted wallet from the future");
  }
 private synchronized void updateChannelInWallet() {
   if (storedChannel == null) return;
   storedChannel.valueToMe = valueToMe;
   StoredPaymentChannelClientStates channels =
       (StoredPaymentChannelClientStates)
           wallet.getExtensions().get(StoredPaymentChannelClientStates.EXTENSION_ID);
   wallet.addOrUpdateExtension(channels);
 }
示例#4
0
  private void writeKeys(@Nonnull final OutputStream os) throws IOException {
    final List<ECKey> keys = new LinkedList<ECKey>();
    for (final ECKey key : wallet.getKeys()) if (!wallet.isKeyRotating(key)) keys.add(key);

    final Writer out = new OutputStreamWriter(os, Constants.UTF_8);
    WalletUtils.writeKeys(out, keys);
    out.close();
  }
 /**
  * Creates the initial multisig contract and incomplete refund transaction which can be requested
  * at the appropriate time using {@link PaymentChannelClientState#getIncompleteRefundTransaction}
  * and {@link PaymentChannelClientState#getMultisigContract()}. The way the contract is crafted
  * can be adjusted by overriding {@link
  * PaymentChannelClientState#editContractSendRequest(com.google.bitcoin.core.Wallet.SendRequest)}.
  * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be
  * relatively low.
  *
  * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the
  *     network
  * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate
  */
 public synchronized void initiate() throws ValueOutOfRangeException, InsufficientMoneyException {
   final NetworkParameters params = wallet.getParams();
   Transaction template = new Transaction(params);
   // We always place the client key before the server key because, if either side wants some
   // privacy, they can
   // use a fresh key for the the multisig contract and nowhere else
   List<ECKey> keys = Lists.newArrayList(myKey, serverMultisigKey);
   // There is also probably a change output, but we don't bother shuffling them as it's obvious
   // from the
   // format which one is the change. If we start obfuscating the change output better in future
   // this may
   // be worth revisiting.
   TransactionOutput multisigOutput =
       template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys));
   if (multisigOutput.getMinNonDustValue().compareTo(totalValue) > 0)
     throw new ValueOutOfRangeException("totalValue too small to use");
   Wallet.SendRequest req = Wallet.SendRequest.forTx(template);
   req.coinSelector = AllowUnconfirmedCoinSelector.get();
   editContractSendRequest(req);
   req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable.
   wallet.completeTx(req);
   Coin multisigFee = req.tx.getFee();
   multisigContract = req.tx;
   // Build a refund transaction that protects us in the case of a bad server that's just trying to
   // cause havoc
   // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so
   // the server
   // has an assurance that we cannot take back our money by claiming a refund before the channel
   // closes - this
   // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will
   // need to change
   // in future as it breaks the intended design of timelocking/tx replacement, but for now it
   // simplifies this
   // specific protocol somewhat.
   refundTx = new Transaction(params);
   refundTx
       .addInput(multisigOutput)
       .setSequenceNumber(0); // Allow replacement when it's eventually reactivated.
   refundTx.setLockTime(expiryTime);
   if (totalValue.compareTo(Coin.CENT) < 0) {
     // Must pay min fee.
     final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
     if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0)
       throw new ValueOutOfRangeException("totalValue too small to use");
     refundTx.addOutput(valueAfterFee, myKey.toAddress(params));
     refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE);
   } else {
     refundTx.addOutput(totalValue, myKey.toAddress(params));
     refundFees = multisigFee;
   }
   refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF);
   log.info(
       "initiated channel with multi-sig contract {}, refund {}",
       multisigContract.getHashAsString(),
       refundTx.getHashAsString());
   state = State.INITIATED;
   // Client should now call getIncompleteRefundTransaction() and send it to the server.
 }
  @Override
  public void onUpdate(
      final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
    final WalletApplication application = (WalletApplication) context.getApplicationContext();
    final Wallet wallet = application.getWallet();
    final BigInteger balance = wallet.getBalance(BalanceType.ESTIMATED);

    updateWidgets(context, appWidgetManager, appWidgetIds, balance);
  }
 private synchronized void deleteChannelFromWallet() {
   log.info("Close tx has confirmed, deleting channel from wallet: {}", storedChannel);
   StoredPaymentChannelClientStates channels =
       (StoredPaymentChannelClientStates)
           wallet.getExtensions().get(StoredPaymentChannelClientStates.EXTENSION_ID);
   channels.removeChannel(storedChannel);
   wallet.addOrUpdateExtension(channels);
   storedChannel = null;
 }
示例#8
0
  private static Wallet readKeys(@Nonnull final InputStream is) throws IOException {
    final BufferedReader in = new BufferedReader(new InputStreamReader(is, Constants.UTF_8));
    final List<ECKey> keys = WalletUtils.readKeys(in);
    in.close();

    final Wallet wallet = new Wallet(Constants.NETWORK_PARAMETERS);
    for (final ECKey key : keys) wallet.addKey(key);

    return wallet;
  }
 private synchronized Transaction makeUnsignedChannelContract(Coin valueToMe)
     throws ValueOutOfRangeException {
   Transaction tx = new Transaction(wallet.getParams());
   tx.addInput(multisigContract.getOutput(0));
   // Our output always comes first.
   // TODO: We should drop myKey in favor of output key + multisig key separation
   // (as its always obvious who the client is based on T2 output order)
   tx.addOutput(valueToMe, myKey.toAddress(wallet.getParams()));
   return tx;
 }
 @VisibleForTesting
 synchronized void doStoreChannelInWallet(Sha256Hash id) {
   StoredPaymentChannelClientStates channels =
       (StoredPaymentChannelClientStates)
           wallet.getExtensions().get(StoredPaymentChannelClientStates.EXTENSION_ID);
   checkNotNull(
       channels,
       "You have not added the StoredPaymentChannelClientStates extension to the wallet.");
   checkState(channels.getChannel(id, multisigContract.getHash()) == null);
   storedChannel =
       new StoredClientChannel(id, multisigContract, refundTx, myKey, valueToMe, refundFees, true);
   channels.putChannel(storedChannel);
   wallet.addOrUpdateExtension(channels);
 }
示例#11
0
  public Address determineSelectedAddress() {
    final String selectedAddress = prefs.getString(Constants.PREFS_KEY_SELECTED_ADDRESS, null);

    Address firstAddress = null;
    for (final ECKey key : wallet.getKeys()) {
      if (!wallet.isKeyRotating(key)) {
        final Address address = key.toAddress(Constants.NETWORK_PARAMETERS);

        if (address.toString().equals(selectedAddress)) return address;

        if (firstAddress == null) firstAddress = address;
      }
    }

    return firstAddress;
  }
 private synchronized void initWalletListeners() {
   // Register a listener that watches out for the server closing the channel.
   if (storedChannel != null && storedChannel.close != null) {
     watchCloseConfirmations();
   }
   wallet.addEventListener(
       new AbstractWalletEventListener() {
         @Override
         public void onCoinsReceived(
             Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
           synchronized (PaymentChannelClientState.this) {
             if (multisigContract == null) return;
             if (isSettlementTransaction(tx)) {
               log.info(
                   "Close: transaction {} closed contract {}",
                   tx.getHash(),
                   multisigContract.getHash());
               // Record the fact that it was closed along with the transaction that closed it.
               state = State.CLOSED;
               if (storedChannel == null) return;
               storedChannel.close = tx;
               updateChannelInWallet();
               watchCloseConfirmations();
             }
           }
         }
       },
       Threading.SAME_THREAD);
 }
  @Override
  protected void onStopLoading() {
    wallet.removeEventListener(walletChangeListener);
    walletChangeListener.removeCallbacks();

    super.onStopLoading();
  }
示例#14
0
  public void addNewKeyToWallet() {
    wallet.addKey(new ECKey());

    backupKeys();

    prefs.edit().putBoolean(Constants.PREFS_KEY_REMIND_BACKUP, true).commit();
  }
  @Override
  protected void onStartLoading() {
    super.onStartLoading();

    wallet.addEventListener(walletChangeListener, Threading.SAME_THREAD);

    forceLoad();
  }
示例#16
0
  @Override
  protected void onStartLoading() {
    super.onStartLoading();

    wallet.addEventListener(walletChangeListener);

    forceLoad();
  }
 /** Skips saving state in the wallet for testing */
 @VisibleForTesting
 synchronized void fakeSave() {
   try {
     wallet.commitTx(multisigContract);
   } catch (VerificationException e) {
     throw new RuntimeException(e); // We created it
   }
   state = State.PROVIDE_MULTISIG_CONTRACT_TO_SERVER;
 }
 private static void populateExtensions(Wallet wallet, Protos.Wallet.Builder walletBuilder) {
   for (WalletExtension extension : wallet.getExtensions().values()) {
     Protos.Extension.Builder proto = Protos.Extension.newBuilder();
     proto.setId(extension.getWalletExtensionID());
     proto.setMandatory(extension.isWalletExtensionMandatory());
     proto.setData(ByteString.copyFrom(extension.serializeWalletExtension()));
     walletBuilder.addExtension(proto);
   }
 }
 /**
  * Removes the channel with the given id from this set of stored states and notifies the wallet of
  * an update to this wallet extension.
  *
  * <p>Note that the channel will still have its contract and refund transactions broadcast via the
  * connected {@link TransactionBroadcaster} as long as this {@link
  * StoredPaymentChannelClientStates} continues to exist in memory.
  */
 void removeChannel(StoredClientChannel channel) {
   lock.lock();
   try {
     mapChannels.remove(channel.id, channel);
   } finally {
     lock.unlock();
   }
   containingWallet.addOrUpdateExtension(this);
 }
    @Override
    public Set<Transaction> loadInBackground() {
      final Set<Transaction> transactions = wallet.getTransactions(true);

      final Set<Transaction> filteredTransactions = new HashSet<Transaction>(transactions.size());
      for (final Transaction tx : transactions) {
        final Map<Sha256Hash, Integer> appearsIn = tx.getAppearsInHashes();
        if (appearsIn != null && !appearsIn.isEmpty()) // TODO filter by updateTime
        filteredTransactions.add(tx);
      }

      return filteredTransactions;
    }
  /**
   * Stores this channel's state in the wallet as a part of a {@link
   * StoredPaymentChannelClientStates} wallet extension and keeps it up-to-date each time payment is
   * incremented. This allows the {@link StoredPaymentChannelClientStates} object to keep track of
   * timeouts and broadcast the refund transaction when the channel expires.
   *
   * <p>A channel may only be stored after it has fully opened (ie state == State.READY). The wallet
   * provided in the constructor must already have a {@link StoredPaymentChannelClientStates} object
   * in its extensions set.
   *
   * @param id A hash providing this channel with an id which uniquely identifies this server. It
   *     does not have to be unique.
   */
  public synchronized void storeChannelInWallet(Sha256Hash id) {
    checkState(state == State.SAVE_STATE_IN_WALLET && id != null);
    if (storedChannel != null) {
      checkState(storedChannel.id.equals(id));
      return;
    }
    doStoreChannelInWallet(id);

    try {
      wallet.commitTx(multisigContract);
    } catch (VerificationException e) {
      throw new RuntimeException(e); // We created it
    }
    state = State.PROVIDE_MULTISIG_CONTRACT_TO_SERVER;
  }
示例#22
0
  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");
  }
 private static void loadExtensions(Wallet wallet, Protos.Wallet walletProto) {
   final Map<String, WalletExtension> extensions = wallet.getExtensions();
   for (Protos.Extension extProto : walletProto.getExtensionList()) {
     String id = extProto.getId();
     WalletExtension extension = extensions.get(id);
     if (extension == null) {
       if (extProto.getMandatory()) {
         throw new IllegalArgumentException("Unknown mandatory extension in wallet: " + id);
       }
     } else {
       log.info("Loading wallet extension {}", id);
       try {
         extension.deserializeWalletExtension(wallet, extProto.getData().toByteArray());
       } catch (Exception e) {
         if (extProto.getMandatory())
           throw new IllegalArgumentException("Unknown mandatory extension in wallet: " + id);
       }
     }
   }
 }
  public void setUp(BlockStore blockStore) throws Exception {
    BriefLogFormatter.init();

    unitTestParams = UnitTestParams.get();
    Wallet.SendRequest.DEFAULT_FEE_PER_KB = BigInteger.ZERO;
    this.blockStore = blockStore;
    wallet = new Wallet(unitTestParams);
    key = new ECKey();
    address = key.toAddress(unitTestParams);
    wallet.addKey(key);
    blockChain = new BlockChain(unitTestParams, wallet, blockStore);

    startPeerServers();
    if (clientType == ClientType.NIO_CLIENT_MANAGER
        || clientType == ClientType.BLOCKING_CLIENT_MANAGER) {
      channels.startAsync();
      channels.awaitRunning();
    }

    socketAddress = new InetSocketAddress("127.0.0.1", 1111);
  }
 // 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() {
             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) containingWallet.addOrUpdateExtension(this);
 }
  /**
   * Converts the given wallet to the object representation of the protocol buffers. This can be
   * modified, or additional data fields set, before serialization takes place.
   */
  public Protos.Wallet walletToProto(Wallet wallet) {
    Protos.Wallet.Builder walletBuilder = Protos.Wallet.newBuilder();
    walletBuilder.setNetworkIdentifier(wallet.getNetworkParameters().getId());
    if (wallet.getDescription() != null) {
      walletBuilder.setDescription(wallet.getDescription());
    }

    for (WalletTransaction wtx : wallet.getWalletTransactions()) {
      Protos.Transaction txProto = makeTxProto(wtx);
      walletBuilder.addTransaction(txProto);
    }

    for (ECKey key : wallet.getKeys()) {
      Protos.Key.Builder keyBuilder =
          Protos.Key.newBuilder()
              .setCreationTimestamp(key.getCreationTimeSeconds() * 1000)
              // .setLabel() TODO
              .setType(Protos.Key.Type.ORIGINAL);
      if (key.getPrivKeyBytes() != null)
        keyBuilder.setPrivateKey(ByteString.copyFrom(key.getPrivKeyBytes()));

      EncryptedPrivateKey encryptedPrivateKey = key.getEncryptedPrivateKey();
      if (encryptedPrivateKey != null) {
        // Key is encrypted.
        Protos.EncryptedPrivateKey.Builder encryptedKeyBuilder =
            Protos.EncryptedPrivateKey.newBuilder()
                .setEncryptedPrivateKey(
                    ByteString.copyFrom(encryptedPrivateKey.getEncryptedBytes()))
                .setInitialisationVector(
                    ByteString.copyFrom(encryptedPrivateKey.getInitialisationVector()));

        if (key.getKeyCrypter() == null) {
          throw new IllegalStateException(
              "The encrypted key " + key.toString() + " has no KeyCrypter.");
        } else {
          // If it is a Scrypt + AES encrypted key, set the persisted key type.
          if (key.getKeyCrypter().getUnderstoodEncryptionType()
              == Protos.Wallet.EncryptionType.ENCRYPTED_SCRYPT_AES) {
            keyBuilder.setType(Protos.Key.Type.ENCRYPTED_SCRYPT_AES);
          } else {
            throw new IllegalArgumentException(
                "The key "
                    + key.toString()
                    + " is encrypted with a KeyCrypter of type "
                    + key.getKeyCrypter().getUnderstoodEncryptionType()
                    + ". This WalletProtobufSerialiser does not understand that type of encryption.");
          }
        }
        keyBuilder.setEncryptedPrivateKey(encryptedKeyBuilder);
      }

      // We serialize the public key even if the private key is present for speed reasons: we don't
      // want to do
      // lots of slow EC math to load the wallet, we prefer to store the redundant data instead. It
      // matters more
      // on mobile platforms.
      keyBuilder.setPublicKey(ByteString.copyFrom(key.getPubKey()));
      walletBuilder.addKey(keyBuilder);
    }

    // Populate the lastSeenBlockHash field.
    Sha256Hash lastSeenBlockHash = wallet.getLastBlockSeenHash();
    if (lastSeenBlockHash != null) {
      walletBuilder.setLastSeenBlockHash(hashToByteString(lastSeenBlockHash));
      walletBuilder.setLastSeenBlockHeight(wallet.getLastBlockSeenHeight());
    }

    // Populate the scrypt parameters.
    KeyCrypter keyCrypter = wallet.getKeyCrypter();
    if (keyCrypter == null) {
      // The wallet is unencrypted.
      walletBuilder.setEncryptionType(EncryptionType.UNENCRYPTED);
    } else {
      // The wallet is encrypted.
      walletBuilder.setEncryptionType(keyCrypter.getUnderstoodEncryptionType());
      if (keyCrypter instanceof KeyCrypterScrypt) {
        KeyCrypterScrypt keyCrypterScrypt = (KeyCrypterScrypt) keyCrypter;
        walletBuilder.setEncryptionParameters(keyCrypterScrypt.getScryptParameters());
      } else {
        // Some other form of encryption has been specified that we do not know how to persist.
        throw new RuntimeException(
            "The wallet has encryption of type '"
                + keyCrypter.getUnderstoodEncryptionType()
                + "' but this WalletProtobufSerializer does not know how to persist this.");
      }
    }

    populateExtensions(wallet, walletBuilder);

    // Populate the wallet version.
    walletBuilder.setVersion(wallet.getVersion());

    return walletBuilder.build();
  }
  /**
   * Loads wallet data from the given protocol buffer and inserts it into the given Wallet object.
   * This is primarily useful when you wish to pre-register extension objects. Note that if loading
   * fails the provided Wallet object may be in an indeterminate state and should be thrown away.
   *
   * @throws IOException if there is a problem reading the stream.
   * @throws IllegalArgumentException if the wallet is corrupt.
   */
  public void readWallet(Protos.Wallet walletProto, Wallet wallet) throws IOException {
    // TODO: This method should throw more specific exception types than IllegalArgumentException.
    // Read the scrypt parameters that specify how encryption and decryption is performed.
    if (walletProto.hasEncryptionParameters()) {
      Protos.ScryptParameters encryptionParameters = walletProto.getEncryptionParameters();
      wallet.setKeyCrypter(new KeyCrypterScrypt(encryptionParameters));
    }

    if (walletProto.hasDescription()) {
      wallet.setDescription(walletProto.getDescription());
    }

    // Read all keys
    for (Protos.Key keyProto : walletProto.getKeyList()) {
      if (!(keyProto.getType() == Protos.Key.Type.ORIGINAL
          || keyProto.getType() == Protos.Key.Type.ENCRYPTED_SCRYPT_AES)) {
        throw new IllegalArgumentException(
            "Unknown key type in wallet, type = " + keyProto.getType());
      }

      byte[] privKey = keyProto.hasPrivateKey() ? keyProto.getPrivateKey().toByteArray() : null;
      EncryptedPrivateKey encryptedPrivateKey = null;
      if (keyProto.hasEncryptedPrivateKey()) {
        Protos.EncryptedPrivateKey encryptedPrivateKeyProto = keyProto.getEncryptedPrivateKey();
        encryptedPrivateKey =
            new EncryptedPrivateKey(
                encryptedPrivateKeyProto.getInitialisationVector().toByteArray(),
                encryptedPrivateKeyProto.getEncryptedPrivateKey().toByteArray());
      }

      byte[] pubKey = keyProto.hasPublicKey() ? keyProto.getPublicKey().toByteArray() : null;

      ECKey ecKey;
      final KeyCrypter keyCrypter = wallet.getKeyCrypter();
      if (keyCrypter != null
          && keyCrypter.getUnderstoodEncryptionType() != EncryptionType.UNENCRYPTED) {
        // If the key is encrypted construct an ECKey using the encrypted private key bytes.
        ecKey = new ECKey(encryptedPrivateKey, pubKey, keyCrypter);
      } else {
        // Construct an unencrypted private key.
        ecKey = new ECKey(privKey, pubKey);
      }
      ecKey.setCreationTimeSeconds((keyProto.getCreationTimestamp() + 500) / 1000);
      wallet.addKey(ecKey);
    }

    // Read all transactions and insert into the txMap.
    for (Protos.Transaction txProto : walletProto.getTransactionList()) {
      readTransaction(txProto, wallet.getParams());
    }

    // Update transaction outputs to point to inputs that spend them
    for (Protos.Transaction txProto : walletProto.getTransactionList()) {
      WalletTransaction wtx = connectTransactionOutputs(txProto);
      wallet.addWalletTransaction(wtx);
    }

    // Update the lastBlockSeenHash.
    if (!walletProto.hasLastSeenBlockHash()) {
      wallet.setLastBlockSeenHash(null);
    } else {
      wallet.setLastBlockSeenHash(byteStringToHash(walletProto.getLastSeenBlockHash()));
    }
    if (!walletProto.hasLastSeenBlockHeight()) {
      wallet.setLastBlockSeenHeight(-1);
    } else {
      wallet.setLastBlockSeenHeight(walletProto.getLastSeenBlockHeight());
    }

    loadExtensions(wallet, walletProto);

    if (walletProto.hasVersion()) {
      wallet.setVersion(walletProto.getVersion());
    }

    // Make sure the object can be re-used to read another wallet without corruption.
    txMap.clear();
  }
  @Override
  public View onCreateView(
      final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
    final View view = inflater.inflate(R.layout.request_coins_fragment, container, false);

    qrView = (ImageView) view.findViewById(R.id.request_coins_qr);
    qrView.setOnClickListener(
        new OnClickListener() {
          @Override
          public void onClick(final View v) {
            BitmapFragment.show(getFragmentManager(), qrCodeBitmap);
          }
        });

    final CurrencyAmountView btcAmountView =
        (CurrencyAmountView) view.findViewById(R.id.request_coins_amount_btc);
    btcAmountView.setCurrencySymbol(config.getBtcPrefix());
    btcAmountView.setInputPrecision(config.getBtcMaxPrecision());
    btcAmountView.setHintPrecision(config.getBtcPrecision());
    btcAmountView.setShift(config.getBtcShift());

    final CurrencyAmountView localAmountView =
        (CurrencyAmountView) view.findViewById(R.id.request_coins_amount_local);
    localAmountView.setInputPrecision(Constants.LOCAL_PRECISION);
    localAmountView.setHintPrecision(Constants.LOCAL_PRECISION);
    amountCalculatorLink = new CurrencyCalculatorLink(btcAmountView, localAmountView);

    addressView = (Spinner) view.findViewById(R.id.request_coins_fragment_address);
    final List<ECKey> keys = new LinkedList<ECKey>();
    for (final ECKey key : application.getWallet().getKeys())
      if (!wallet.isKeyRotating(key)) keys.add(key);
    final WalletAddressesAdapter adapter = new WalletAddressesAdapter(activity, wallet, false);
    adapter.replace(keys);
    addressView.setAdapter(adapter);
    final Address selectedAddress = application.determineSelectedAddress();
    for (int i = 0; i < keys.size(); i++) {
      final Address address = keys.get(i).toAddress(Constants.NETWORK_PARAMETERS);
      if (address.equals(selectedAddress)) {
        addressView.setSelection(i);
        break;
      }
    }

    acceptBluetoothPaymentView =
        (CheckBox) view.findViewById(R.id.request_coins_accept_bluetooth_payment);
    acceptBluetoothPaymentView.setVisibility(
        ENABLE_BLUETOOTH_LISTENING && bluetoothAdapter != null ? View.VISIBLE : View.GONE);
    acceptBluetoothPaymentView.setChecked(
        ENABLE_BLUETOOTH_LISTENING && bluetoothAdapter != null && bluetoothAdapter.isEnabled());
    acceptBluetoothPaymentView.setOnCheckedChangeListener(
        new OnCheckedChangeListener() {
          @Override
          public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
            if (ENABLE_BLUETOOTH_LISTENING && bluetoothAdapter != null && isChecked) {
              if (bluetoothAdapter.isEnabled()) {
                startBluetoothListening();
              } else {
                // ask for permission to enable bluetooth
                startActivityForResult(
                    new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE),
                    REQUEST_CODE_ENABLE_BLUETOOTH);
              }
            } else {
              stopBluetoothListening();
            }

            updateView();
          }
        });

    initiateRequestView =
        (TextView) view.findViewById(R.id.request_coins_fragment_initiate_request);

    return view;
  }
示例#29
0
  @Override
  public void onCreate() {
    new LinuxSecureRandom(); // init proper random number generator

    initLogging();

    StrictMode.setThreadPolicy(
        new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .permitDiskReads()
            .permitDiskWrites()
            .penaltyLog()
            .build());

    Threading.throwOnLockCycles();

    log.info(
        "configuration: "
            + (Constants.TEST ? "test" : "prod")
            + ", "
            + Constants.NETWORK_PARAMETERS.getId());

    super.onCreate();

    try {
      packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
    } catch (final NameNotFoundException x) {
      throw new RuntimeException(x);
    }

    CrashReporter.init(getCacheDir());

    Threading.uncaughtExceptionHandler =
        new Thread.UncaughtExceptionHandler() {
          @Override
          public void uncaughtException(final Thread thread, final Throwable throwable) {
            log.info("bitcoinj uncaught exception", throwable);
            CrashReporter.saveBackgroundTrace(throwable, packageInfo);
          }
        };

    prefs = PreferenceManager.getDefaultSharedPreferences(this);
    activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

    blockchainServiceIntent = new Intent(this, BlockchainServiceImpl.class);
    blockchainServiceCancelCoinsReceivedIntent =
        new Intent(
            BlockchainService.ACTION_CANCEL_COINS_RECEIVED,
            null,
            this,
            BlockchainServiceImpl.class);
    blockchainServiceResetBlockchainIntent =
        new Intent(
            BlockchainService.ACTION_RESET_BLOCKCHAIN, null, this, BlockchainServiceImpl.class);

    walletFile = getFileStreamPath(Constants.WALLET_FILENAME_PROTOBUF);

    migrateWalletToProtobuf();

    loadWalletFromProtobuf();
    wallet.autosaveToFile(walletFile, 1, TimeUnit.SECONDS, new WalletAutosaveEventListener());

    final int lastVersionCode = prefs.getInt(Constants.PREFS_KEY_LAST_VERSION, 0);
    prefs.edit().putInt(Constants.PREFS_KEY_LAST_VERSION, packageInfo.versionCode).commit();

    if (packageInfo.versionCode > lastVersionCode)
      log.info("detected app upgrade: " + lastVersionCode + " -> " + packageInfo.versionCode);
    else if (packageInfo.versionCode < lastVersionCode)
      log.warn("detected app downgrade: " + lastVersionCode + " -> " + packageInfo.versionCode);

    if (lastVersionCode > 0
        && lastVersionCode < KEY_ROTATION_VERSION_CODE
        && packageInfo.versionCode >= KEY_ROTATION_VERSION_CODE) {
      log.info("detected version jump crossing key rotation");
      wallet.setKeyRotationTime(System.currentTimeMillis() / 1000);
    }

    ensureKey();
  }
示例#30
0
  private void ensureKey() {
    for (final ECKey key : wallet.getKeys()) if (!wallet.isKeyRotating(key)) return; // found

    log.info("wallet has no usable key - creating");
    addNewKeyToWallet();
  }