protected boolean synchronizeUnspentOutputs(Collection<Address> addresses) { // Get the current unspent outputs as dictated by the block chain QueryUnspentOutputsResponse UnspentOutputResponse; try { UnspentOutputResponse = _wapi .queryUnspentOutputs(new QueryUnspentOutputsRequest(Wapi.VERSION, addresses)) .getResult(); } catch (WapiException e) { _logger.logError("Server connection failed with error code: " + e.errorCode, e); postEvent(Event.SERVER_CONNECTION_ERROR); return false; } Collection<TransactionOutputEx> remoteUnspent = UnspentOutputResponse.unspent; // Store the current block height setBlockChainHeight(UnspentOutputResponse.height); // Make a map for fast lookup Map<OutPoint, TransactionOutputEx> remoteMap = toMap(remoteUnspent); // Get the current unspent outputs as it is believed to be locally Collection<TransactionOutputEx> localUnspent = _backing.getAllUnspentOutputs(); // Make a map for fast lookup Map<OutPoint, TransactionOutputEx> localMap = toMap(localUnspent); // Find remotely removed unspent outputs for (TransactionOutputEx l : localUnspent) { TransactionOutputEx r = remoteMap.get(l.outPoint); if (r == null) { // An output has gone. Maybe it was spent in another wallet, or // never confirmed due to missing fees, double spend, or mutated. // Either way, we delete it locally _backing.deleteUnspentOutput(l.outPoint); } } // Find remotely added unspent outputs Set<Sha256Hash> transactionsToAddOrUpdate = new HashSet<Sha256Hash>(); List<TransactionOutputEx> unspentOutputsToAddOrUpdate = new LinkedList<TransactionOutputEx>(); for (TransactionOutputEx r : remoteUnspent) { TransactionOutputEx l = localMap.get(r.outPoint); if (l == null || l.height != r.height) { // New remote output or new height (Maybe it confirmed or we // might even have had a reorg). Either way we just update it unspentOutputsToAddOrUpdate.add(r); transactionsToAddOrUpdate.add(r.outPoint.hash); // Note: We are not adding the unspent output to the DB just yet. We // first want to verify the full set of funding transactions of the // transaction that this unspent output belongs to } } // Fetch updated or added transactions if (transactionsToAddOrUpdate.size() > 0) { GetTransactionsResponse response; try { response = _wapi .getTransactions( new GetTransactionsRequest(Wapi.VERSION, transactionsToAddOrUpdate)) .getResult(); } catch (WapiException e) { _logger.logError("Server connection failed with error code: " + e.errorCode, e); postEvent(Event.SERVER_CONNECTION_ERROR); return false; } try { handleNewExternalTransactions(response.transactions); } catch (WapiException e) { _logger.logError("Server connection failed with error code: " + e.errorCode, e); postEvent(Event.SERVER_CONNECTION_ERROR); return false; } // Finally update out list of unspent outputs with added or updated // outputs for (TransactionOutputEx output : unspentOutputsToAddOrUpdate) { _backing.putUnspentOutput(output); } } return true; }