diff --git a/core/src/main/java/com/google/bitcoin/core/TransactionConfidence.java b/core/src/main/java/com/google/bitcoin/core/TransactionConfidence.java index a36bedde..e1f1969d 100644 --- a/core/src/main/java/com/google/bitcoin/core/TransactionConfidence.java +++ b/core/src/main/java/com/google/bitcoin/core/TransactionConfidence.java @@ -17,6 +17,7 @@ package com.google.bitcoin.core; import com.google.bitcoin.store.BlockStoreException; +import com.google.bitcoin.utils.EventListenerInvoker; import java.io.Serializable; import java.math.BigInteger; @@ -212,14 +213,19 @@ public class TransactionConfidence implements Serializable { /** * Called by a {@link Peer} when a transaction is pending and announced by a peer. The more peers announce the * transaction, the more peers have validated it (assuming your internet connection is not being intercepted). - * If confidence is currently unknown, sets it to {@link ConfidenceType#NOT_SEEN_IN_CHAIN}. + * If confidence is currently unknown, sets it to {@link ConfidenceType#NOT_SEEN_IN_CHAIN}. Listeners will be + * invoked in this case. * * @param address IP address of the peer, used as a proxy for identity. */ public synchronized void markBroadcastBy(PeerAddress address) { broadcastBy.add(address); - if (getConfidenceType() == ConfidenceType.UNKNOWN) + if (getConfidenceType() == ConfidenceType.UNKNOWN) { setConfidenceType(ConfidenceType.NOT_SEEN_IN_CHAIN); + // Listeners are already run by setConfidenceType. + } else { + runListeners(); + } } /** @@ -356,16 +362,11 @@ public class TransactionConfidence implements Serializable { } private void runListeners() { - if (listeners == null) return; - for (int i = 0; i < listeners.size(); i++) { - Listener l = listeners.get(i); - synchronized (l) { - l.onConfidenceChanged(transaction); + EventListenerInvoker.invoke(listeners, new EventListenerInvoker() { + @Override + public void invoke(Listener listener) { + listener.onConfidenceChanged(transaction); } - if (listeners.get(i) != l) { - // Listener removed itself. - i--; - } - } + }); } } diff --git a/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java b/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java index 178c8435..02ba91ef 100644 --- a/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java +++ b/core/src/test/java/com/google/bitcoin/core/PeerGroupTest.java @@ -224,20 +224,32 @@ public class PeerGroupTest extends TestWithNetworkConnections { InventoryMessage inv = new InventoryMessage(params); inv.addTransaction(tx); + final Transaction[] event = new Transaction[1]; + tx.getConfidence().addEventListener(new TransactionConfidence.Listener() { + public void onConfidenceChanged(Transaction tx) { + event[0] = tx; + } + }); + // Peer 2 advertises the tx but does not download it. assertNull(n2.exchange(inv)); assertEquals(0, tx.getConfidence().numBroadcastPeers()); + assertEquals(null, event[0]); // Peer 1 (the download peer) advertises the tx, we download it. n1.exchange(inv); // returns getdata n1.exchange(tx); // returns nothing after a queue drain. // Two peers saw this tx hash. assertEquals(2, tx.getConfidence().numBroadcastPeers()); + assertEquals(tx, event[0]); + event[0] = null; assertTrue(tx.getConfidence().getBroadcastBy().contains(n1.getPeerAddress())); assertTrue(tx.getConfidence().getBroadcastBy().contains(n2.getPeerAddress())); // A straggler reports in. n3.exchange(inv); assertEquals(3, tx.getConfidence().numBroadcastPeers()); assertTrue(tx.getConfidence().getBroadcastBy().contains(n3.getPeerAddress())); + assertEquals(tx, event[0]); + event[0] = null; } @Test