@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(); } }
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); }
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; }
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); }
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(); }
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(); }
@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; }
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; }
@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(); }
private void ensureKey() { for (final ECKey key : wallet.getKeys()) if (!wallet.isKeyRotating(key)) return; // found log.info("wallet has no usable key - creating"); addNewKeyToWallet(); }