From 0ba5f61c884859c792fc725222628eaad7b48a09 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Sun, 1 Mar 2015 20:33:40 +0100 Subject: [PATCH] Delete broadcastBy data once a tx is buried under >100 blocks, as a memory saving. Remove TODO as the code is fairly clear these days. --- .../bitcoinj/core/TransactionConfidence.java | 15 +++++++++++++-- .../main/java/org/bitcoinj/core/Wallet.java | 18 ++++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/TransactionConfidence.java b/core/src/main/java/org/bitcoinj/core/TransactionConfidence.java index 73740c63..0844ff3d 100644 --- a/core/src/main/java/org/bitcoinj/core/TransactionConfidence.java +++ b/core/src/main/java/org/bitcoinj/core/TransactionConfidence.java @@ -339,9 +339,11 @@ public class TransactionConfidence implements Serializable { /** * Called by the wallet when the tx appears on the best chain and a new block is added to the top. Updates the * internal counter that tracks how deeply buried the block is. + * + * @return the new depth */ - public synchronized void incrementDepthInBlocks() { - this.depth++; + public synchronized int incrementDepthInBlocks() { + return ++this.depth; } /** @@ -365,6 +367,15 @@ public class TransactionConfidence implements Serializable { this.depth = depth; } + /** + * Erases the set of broadcast/seen peers. This cannot be called whilst the confidence is PENDING. It is useful + * for saving memory and wallet space once a tx is buried so deep it doesn't seem likely to go pending again. + */ + public void clearBroadcastBy() { + checkState(getConfidenceType() != ConfidenceType.PENDING); + broadcastBy.clear(); + } + /** * If this transaction has been overridden by a double spend (is dead), this call returns the overriding transaction. * Note that this call can return null if you have migrated an old wallet, as pre-Jan 2012 wallets did not diff --git a/core/src/main/java/org/bitcoinj/core/Wallet.java b/core/src/main/java/org/bitcoinj/core/Wallet.java index 3295b356..0bb6ef63 100644 --- a/core/src/main/java/org/bitcoinj/core/Wallet.java +++ b/core/src/main/java/org/bitcoinj/core/Wallet.java @@ -1883,7 +1883,6 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha setLastBlockSeenHash(newBlockHash); setLastBlockSeenHeight(block.getHeight()); setLastBlockSeenTimeSecs(block.getHeader().getTimeSeconds()); - // TODO: Clarify the code below. // Notify all the BUILDING transactions of the new block. // This is so that they can update their depth. Set transactions = getTransactions(true); @@ -1892,9 +1891,20 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha // tx was already processed in receive() due to it appearing in this block, so we don't want to // increment the tx confidence depth twice, it'd result in miscounting. ignoreNextNewBlock.remove(tx.getHash()); - } else if (tx.getConfidence().getConfidenceType() == ConfidenceType.BUILDING) { - tx.getConfidence().incrementDepthInBlocks(); - confidenceChanged.put(tx, TransactionConfidence.Listener.ChangeReason.DEPTH); + } else { + TransactionConfidence confidence = tx.getConfidence(); + if (confidence.getConfidenceType() == ConfidenceType.BUILDING) { + // Erase the set of seen peers once the tx is so deep that it seems unlikely to ever go + // pending again. We could clear this data the moment a tx is seen in the block chain, but + // in cases where the chain re-orgs, this would mean that wallets would perceive a newly + // pending tx has zero confidence at all, which would not be right: we expect it to be + // included once again. We could have a separate was-in-chain-and-now-isn't confidence type + // but this way is backwards compatible with existing software, and the new state probably + // wouldn't mean anything different to just remembering peers anyway. + if (confidence.incrementDepthInBlocks() > 100) + confidence.clearBroadcastBy(); + confidenceChanged.put(tx, TransactionConfidence.Listener.ChangeReason.DEPTH); + } } }