@Override public synchronized boolean deleteTransaction(Sha256Hash transactionId) { TransactionEx tex = _backing.getTransaction(transactionId); if (tex == null) return false; Transaction tx = TransactionEx.toTransaction(tex); _backing.beginTransaction(); try { // See if any of the outputs are stored locally and remove them for (int i = 0; i < tx.outputs.length; i++) { TransactionOutput output = tx.outputs[i]; OutPoint outPoint = new OutPoint(tx.getHash(), i); TransactionOutputEx utxo = _backing.getUnspentOutput(outPoint); if (utxo != null) { _backing.deleteUnspentOutput(outPoint); } } // remove it from the backing _backing.deleteTransaction(transactionId); _backing.setTransactionSuccessful(); } finally { _backing.endTransaction(); } updateLocalBalance(); // will still need a new sync besides re-calculating return true; }
/** * Broadcast outgoing transactions. * * <p>This method should only be called from the wallet manager * * @return false if synchronization failed due to failed blockchain connection */ public synchronized boolean broadcastOutgoingTransactions() { checkNotArchived(); List<Sha256Hash> broadcastedIds = new LinkedList<Sha256Hash>(); Map<Sha256Hash, byte[]> transactions = _backing.getOutgoingTransactions(); for (byte[] rawTransaction : transactions.values()) { TransactionEx tex = TransactionEx.fromUnconfirmedTransaction(rawTransaction); BroadcastResult result = broadcastTransaction(TransactionEx.toTransaction(tex)); if (result == BroadcastResult.SUCCESS) { broadcastedIds.add(tex.txid); _backing.removeOutgoingTransaction(tex.txid); } else { if (result == BroadcastResult.REJECTED) { // invalid tx _backing.deleteTransaction(tex.txid); _backing.removeOutgoingTransaction(tex.txid); } else { // No connection --> retry next sync } } } if (!broadcastedIds.isEmpty()) { onTransactionsBroadcasted(broadcastedIds); } return true; }
/** * Determine whether a transaction was sent from one of our own addresses. * * <p>This is a costly operation as we first have to lookup the transaction and then it's funding * outputs * * @param txid the ID of the transaction to investigate * @return true if one of the funding outputs were sent from one of our own addresses */ protected boolean isFromMe(Sha256Hash txid) { Transaction t = TransactionEx.toTransaction(_backing.getTransaction(txid)); if (t == null) { return false; } return isFromMe(t); }
@Override public TransactionDetails getTransactionDetails(Sha256Hash txid) { // Note that this method is not synchronized, and we might fetch the transaction history while // synchronizing // accounts. That should be ok as we write to the DB in a sane order. TransactionEx tex = _backing.getTransaction(txid); Transaction tx = TransactionEx.toTransaction(tex); if (tx == null) { throw new RuntimeException(); } List<TransactionDetails.Item> inputs = new ArrayList<TransactionDetails.Item>(tx.inputs.length); if (tx.isCoinbase()) { // We have a coinbase transaction. Create one input with the sum of the outputs as its value, // and make the address the null address long value = 0; for (TransactionOutput out : tx.outputs) { value += out.value; } inputs.add(new TransactionDetails.Item(Address.getNullAddress(_network), value, true)); } else { // Populate the inputs for (TransactionInput input : tx.inputs) { Sha256Hash parentHash = input.outPoint.hash; // Get the parent transaction TransactionOutputEx parentOutput = _backing.getParentTransactionOutput(input.outPoint); if (parentOutput == null) { // We never heard about the parent, skip continue; } // Determine the parent address Address parentAddress; ScriptOutput parentScript = ScriptOutput.fromScriptBytes(parentOutput.script); if (parentScript == null) { // Null address means we couldn't figure out the address, strange script parentAddress = Address.getNullAddress(_network); } else { parentAddress = parentScript.getAddress(_network); } inputs.add(new TransactionDetails.Item(parentAddress, parentOutput.value, false)); } } // Populate the outputs TransactionDetails.Item[] outputs = new TransactionDetails.Item[tx.outputs.length]; for (int i = 0; i < tx.outputs.length; i++) { Address address = tx.outputs[i].script.getAddress(_network); outputs[i] = new TransactionDetails.Item(address, tx.outputs[i].value, false); } return new TransactionDetails( txid, tex.height, tex.time, inputs.toArray(new TransactionDetails.Item[] {}), outputs); }