diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java index fabc49fe..52009965 100644 --- a/core/src/main/java/org/bitcoinj/core/Peer.java +++ b/core/src/main/java/org/bitcoinj/core/Peer.java @@ -78,6 +78,7 @@ public class Peer extends PeerSocketHandler { } private final CopyOnWriteArrayList connectionEventListeners; private final CopyOnWriteArrayList> dataEventListeners; + private final CopyOnWriteArrayList> onTransactionEventListeners; // Whether to try and download blocks and transactions from this peer. Set to false by PeerGroup if not the // primary peer. This is to avoid redundant work and concurrency problems with downloading the same chain // in parallel. @@ -217,6 +218,7 @@ public class Peer extends PeerSocketHandler { this.getDataFutures = new CopyOnWriteArrayList(); this.connectionEventListeners = new CopyOnWriteArrayList(); this.dataEventListeners = new CopyOnWriteArrayList>(); + this.onTransactionEventListeners = new CopyOnWriteArrayList>(); this.getAddrFutures = new LinkedList>(); this.fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds(); this.isAcked = false; @@ -255,6 +257,7 @@ public class Peer extends PeerSocketHandler { public void addEventListener(AbstractPeerEventListener listener, Executor executor) { addConnectionEventListener(executor, listener); addDataEventListener(executor, listener); + addOnTransactionBroadcastListener(executor, listener); } /** Deprecated: use the more specific event handler methods instead */ @@ -262,50 +265,39 @@ public class Peer extends PeerSocketHandler { public void removeEventListener(AbstractPeerEventListener listener) { removeConnectionEventListener(listener); removeDataEventListener(listener); + removeOnTransactionBroadcastListener(listener); } - /** - * Registers the given object as an event listener that will be invoked on the user thread. Note that listeners - * added this way will not receive {@link PeerEventListener#getData(Peer, GetDataMessage)} or - * {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because those require that the listener - * be added using {@link Threading#SAME_THREAD}, which requires the other addListener form. - */ + /** Registers a listener that is invoked when a peer is connected or disconnected. */ public void addConnectionEventListener(PeerConnectionEventListener listener) { addConnectionEventListener(Threading.USER_THREAD, listener); } - /** - * Registers the given object as an event listener that will be invoked on the user thread. Note that listeners - * added this way will not receive {@link PeerEventListener#getData(Peer, GetDataMessage)} or - * {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because those require that the listener - * be added using {@link Threading#SAME_THREAD}, which requires the other addListener form. - */ - public void addDataEventListener(PeerDataEventListener listener) { - addDataEventListener(Threading.USER_THREAD, listener); - } - - /** - * Registers the given object as an event listener that will be invoked by the given executor. Note that listeners - * added using any other executor than {@link Threading#SAME_THREAD} will not receive - * {@link PeerEventListener#getData(Peer, GetDataMessage)} or - * {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because this class is not willing to cross - * threads in order to get the results of those hook methods. - */ + /** Registers a listener that is invoked when a peer is connected or disconnected. */ public void addConnectionEventListener(Executor executor, PeerConnectionEventListener listener) { connectionEventListeners.add(new PeerConnectionListenerRegistration(listener, executor)); } - /** - * Registers the given object as an event listener that will be invoked by the given executor. Note that listeners - * added using any other executor than {@link Threading#SAME_THREAD} will not receive - * {@link PeerEventListener#getData(Peer, GetDataMessage)} or - * {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because this class is not willing to cross - * threads in order to get the results of those hook methods. - */ + /** Registers a listener that is called when messages are received. */ + public void addDataEventListener(PeerDataEventListener listener) { + addDataEventListener(Threading.USER_THREAD, listener); + } + + /** Registers a listener that is called when messages are received. */ public void addDataEventListener(Executor executor, PeerDataEventListener listener) { dataEventListeners.add(new ListenerRegistration(executor, listener)); } + /** Registers a listener that is called when a transaction is broadcast across the network */ + public void addOnTransactionBroadcastListener(OnTransactionBroadcastListener listener) { + addOnTransactionBroadcastListener(Threading.USER_THREAD, listener); + } + + /** Registers a listener that is called when a transaction is broadcast across the network */ + public void addOnTransactionBroadcastListener(Executor executor, OnTransactionBroadcastListener listener) { + onTransactionEventListeners.add(new ListenerRegistration(executor, listener)); + } + // Package-local version for PeerGroup void addConnectionEventListenerWithoutOnDisconnect(Executor executor, PeerConnectionEventListener listener) { connectionEventListeners.add(new PeerConnectionListenerRegistration(listener, executor, false)); @@ -319,6 +311,10 @@ public class Peer extends PeerSocketHandler { return ListenerRegistration.removeFromList(listener, dataEventListeners); } + public boolean removeOnTransactionBroadcastListener(OnTransactionBroadcastListener listener) { + return ListenerRegistration.removeFromList(listener, onTransactionEventListeners); + } + @Override public String toString() { PeerAddress addr = getAddress(); @@ -739,7 +735,7 @@ public class Peer extends PeerSocketHandler { } // Tell all listeners about this tx so they can decide whether to keep it or not. If no listener keeps a // reference around then the memory pool will forget about it after a while too because it uses weak references. - for (final ListenerRegistration registration : dataEventListeners) { + for (final ListenerRegistration registration : onTransactionEventListeners) { registration.executor.execute(new Runnable() { @Override public void run() { diff --git a/core/src/main/java/org/bitcoinj/core/PeerGroup.java b/core/src/main/java/org/bitcoinj/core/PeerGroup.java index c28e1b53..254457ca 100644 --- a/core/src/main/java/org/bitcoinj/core/PeerGroup.java +++ b/core/src/main/java/org/bitcoinj/core/PeerGroup.java @@ -26,13 +26,7 @@ import com.google.common.util.concurrent.*; import com.squareup.okhttp.*; import com.subgraph.orchid.*; import net.jcip.annotations.*; -import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener; -import org.bitcoinj.core.listeners.AbstractPeerDataEventListener; -import org.bitcoinj.core.listeners.AbstractWalletEventListener; -import org.bitcoinj.core.listeners.DownloadProgressTracker; -import org.bitcoinj.core.listeners.PeerConnectionEventListener; -import org.bitcoinj.core.listeners.PeerDataEventListener; -import org.bitcoinj.core.listeners.WalletEventListener; +import org.bitcoinj.core.listeners.*; import org.bitcoinj.crypto.*; import org.bitcoinj.net.*; import org.bitcoinj.net.discovery.*; @@ -119,10 +113,11 @@ public class PeerGroup implements TransactionBroadcaster { @GuardedBy("lock") private Peer downloadPeer; // Callback for events related to chain download. @Nullable @GuardedBy("lock") private PeerDataEventListener downloadListener; - // Callbacks for events related to peer connection/disconnection - private final CopyOnWriteArrayList> peerConnectionEventListeners; - // Callbacks for events related to peer data being received - private final CopyOnWriteArrayList> peerDataEventListeners; + /** Callbacks for events related to peer connection/disconnection */ + protected final CopyOnWriteArrayList> peerConnectionEventListeners; + /** Callbacks for events related to peer data being received */ + protected final CopyOnWriteArrayList> peerDataEventListeners; + protected final CopyOnWriteArrayList> onTransactionBroadastEventListeners; // Peer discovery sources, will be polled occasionally if there aren't enough inactives. private final CopyOnWriteArraySet peerDiscoverers; // The version message to use for new connections. @@ -411,6 +406,7 @@ public class PeerGroup implements TransactionBroadcaster { peerDiscoverers = new CopyOnWriteArraySet(); peerConnectionEventListeners = new CopyOnWriteArrayList>(); peerDataEventListeners = new CopyOnWriteArrayList>(); + onTransactionBroadastEventListeners = new CopyOnWriteArrayList>(); runningBroadcasts = Collections.synchronizedSet(new HashSet()); bloomFilterMerger = new FilterMerger(DEFAULT_BLOOM_FILTER_FP_RATE); } @@ -691,17 +687,7 @@ public class PeerGroup implements TransactionBroadcaster { peer.addConnectionEventListener(executor, listener); } - /** - *

Adds a listener that will be notified on the given executor when:

- *
    - *
  1. New peers are connected to.
  2. - *
  3. Peers are disconnected from.
  4. - *
  5. A message is received by the download peer (there is always one peer which is elected as a peer which - * will be used to retrieve data). - *
  6. Blocks are downloaded by the download peer.
  7. - * - *
- */ + /** See {@link Peer#addDataEventListener(Executor, PeerDataEventListener)} */ public void addDataEventListener(final Executor executor, final PeerDataEventListener listener) { peerDataEventListeners.add(new ListenerRegistration(executor, checkNotNull(listener))); for (Peer peer : getConnectedPeers()) @@ -710,22 +696,30 @@ public class PeerGroup implements TransactionBroadcaster { peer.addDataEventListener(executor, listener); } - /** - * Same as {@link PeerGroup#addEventListener(PeerEventListener, java.util.concurrent.Executor)} but defaults - * to running on the user thread. - */ - public void addConnectionEventListener(PeerConnectionEventListener listener) { - addConnectionEventListener(Threading.USER_THREAD, listener); - } - - /** - * Same as {@link PeerGroup#addEventListener(PeerEventListener, java.util.concurrent.Executor)} but defaults - * to running on the user thread. - */ + /** See {@link Peer#addDataEventListener(PeerDataEventListener)} */ public void addDataEventListener(PeerDataEventListener listener) { addDataEventListener(Threading.USER_THREAD, listener); } + /** See {@link Peer#addOnTransactionBroadcastListener(OnTransactionBroadcastListener)} */ + public void addOnTransactionBroadcastListener(OnTransactionBroadcastListener listener) { + addOnTransactionBroadcastListener(Threading.USER_THREAD, listener); + } + + /** See {@link Peer#addOnTransactionBroadcastListener(OnTransactionBroadcastListener)} */ + public void addOnTransactionBroadcastListener(Executor executor, OnTransactionBroadcastListener listener) { + onTransactionBroadastEventListeners.add(new ListenerRegistration(executor, checkNotNull(listener))); + for (Peer peer : getConnectedPeers()) + peer.addOnTransactionBroadcastListener(executor, listener); + for (Peer peer: getPendingPeers()) + peer.addOnTransactionBroadcastListener(executor, listener); + } + + /** See {@link Peer#addConnectionEventListener(PeerConnectionEventListener)} */ + public void addConnectionEventListener(PeerConnectionEventListener listener) { + addConnectionEventListener(Threading.USER_THREAD, listener); + } + /** The given event listener will no longer be called with events. */ public boolean removeConnectionEventListener(PeerConnectionEventListener listener) { boolean result = ListenerRegistration.removeFromList(listener, peerConnectionEventListeners); @@ -746,12 +740,14 @@ public class PeerGroup implements TransactionBroadcaster { return result; } - /** - * Removes all event listeners simultaneously. Note that this includes listeners added internally by the framework - * so it's generally not advised to use this - it exists for special purposes only. - */ - public void clearEventListeners() { - peerConnectionEventListeners.clear(); + /** The given event listener will no longer be called with events. */ + public boolean removeOnTransactionBroadcastListener(OnTransactionBroadcastListener listener) { + boolean result = ListenerRegistration.removeFromList(listener, onTransactionBroadastEventListeners); + for (Peer peer : getConnectedPeers()) + peer.removeOnTransactionBroadcastListener(listener); + for (Peer peer : getPendingPeers()) + peer.removeOnTransactionBroadcastListener(listener); + return result; } /** @@ -1393,12 +1389,12 @@ public class PeerGroup implements TransactionBroadcaster { // Make sure the peer knows how to upload transactions that are requested from us. peer.addDataEventListener(Threading.SAME_THREAD, peerListener); // And set up event listeners for clients. This will allow them to find out about new transactions and blocks. - for (ListenerRegistration registration : peerConnectionEventListeners) { + for (ListenerRegistration registration : peerConnectionEventListeners) peer.addConnectionEventListenerWithoutOnDisconnect(registration.executor, registration.listener); - } - for (ListenerRegistration registration : peerDataEventListeners) { + for (ListenerRegistration registration : peerDataEventListeners) peer.addDataEventListener(registration.executor, registration.listener); - } + for (ListenerRegistration registration : onTransactionBroadastEventListeners) + peer.addOnTransactionBroadcastListener(registration.executor, registration.listener); } finally { lock.unlock(); } @@ -1564,9 +1560,10 @@ public class PeerGroup implements TransactionBroadcaster { } final int fNumConnectedPeers = numConnectedPeers; - for (ListenerRegistration registration : peerDataEventListeners) { + for (ListenerRegistration registration : peerDataEventListeners) peer.removeDataEventListener(registration.listener); - } + for (ListenerRegistration registration : onTransactionBroadastEventListeners) + peer.removeOnTransactionBroadcastListener(registration.listener); for (final ListenerRegistration registration : peerConnectionEventListeners) { registration.executor.execute(new Runnable() { @Override diff --git a/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerDataEventListener.java b/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerDataEventListener.java index a5c52eed..787534d7 100644 --- a/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerDataEventListener.java +++ b/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerDataEventListener.java @@ -16,14 +16,10 @@ package org.bitcoinj.core.listeners; -import org.bitcoinj.core.Block; -import org.bitcoinj.core.FilteredBlock; -import org.bitcoinj.core.GetDataMessage; -import org.bitcoinj.core.Message; -import org.bitcoinj.core.Peer; -import org.bitcoinj.core.Transaction; +import org.bitcoinj.core.*; + import javax.annotation.*; -import java.util.List; +import java.util.*; /** * Deprecated: implement the more specific event listener interfaces instead to fill out only what you need @@ -44,10 +40,6 @@ public abstract class AbstractPeerDataEventListener implements PeerDataEventList return m; } - @Override - public void onTransaction(Peer peer, Transaction t) { - } - @Override public List getData(Peer peer, GetDataMessage m) { return null; diff --git a/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerEventListener.java b/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerEventListener.java index 51e64967..c5ab7099 100644 --- a/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerEventListener.java +++ b/core/src/main/java/org/bitcoinj/core/listeners/AbstractPeerEventListener.java @@ -31,7 +31,7 @@ import java.util.Set; * Deprecated: implement the more specific event listener interfaces instead to fill out only what you need */ @Deprecated -public abstract class AbstractPeerEventListener extends AbstractPeerDataEventListener implements PeerConnectionEventListener { +public abstract class AbstractPeerEventListener extends AbstractPeerDataEventListener implements PeerConnectionEventListener, OnTransactionBroadcastListener { @Override public void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) { } diff --git a/core/src/main/java/org/bitcoinj/core/listeners/OnTransactionBroadcastListener.java b/core/src/main/java/org/bitcoinj/core/listeners/OnTransactionBroadcastListener.java new file mode 100644 index 00000000..df0b1146 --- /dev/null +++ b/core/src/main/java/org/bitcoinj/core/listeners/OnTransactionBroadcastListener.java @@ -0,0 +1,13 @@ +package org.bitcoinj.core.listeners; + +import org.bitcoinj.core.*; + +/** + * Called when a new transaction is broadcast over the network. + */ +public interface OnTransactionBroadcastListener { + /** + * Called when a new transaction is broadcast over the network. + */ + void onTransaction(Peer peer, Transaction t); +} diff --git a/core/src/main/java/org/bitcoinj/core/listeners/PeerDataEventListener.java b/core/src/main/java/org/bitcoinj/core/listeners/PeerDataEventListener.java index 3e7d0fa2..36bbed34 100644 --- a/core/src/main/java/org/bitcoinj/core/listeners/PeerDataEventListener.java +++ b/core/src/main/java/org/bitcoinj/core/listeners/PeerDataEventListener.java @@ -16,14 +16,10 @@ package org.bitcoinj.core.listeners; -import org.bitcoinj.core.Block; -import org.bitcoinj.core.FilteredBlock; -import org.bitcoinj.core.GetDataMessage; -import org.bitcoinj.core.Message; -import org.bitcoinj.core.Peer; -import org.bitcoinj.core.Transaction; -import javax.annotation.Nullable; -import java.util.List; +import org.bitcoinj.core.*; + +import javax.annotation.*; +import java.util.*; /** *

Implementors can listen to events like blocks being downloaded/transactions being broadcast/connect/disconnects, @@ -65,11 +61,6 @@ public interface PeerDataEventListener { */ Message onPreMessageReceived(Peer peer, Message m); - /** - * Called when a new transaction is broadcast over the network. - */ - void onTransaction(Peer peer, Transaction t); - /** *

Called when a peer receives a getdata message, usually in response to an "inv" being broadcast. Return as many * items as possible which appear in the {@link GetDataMessage}, or null if you're not interested in responding.

diff --git a/core/src/main/java/org/bitcoinj/jni/NativePeerEventListener.java b/core/src/main/java/org/bitcoinj/jni/NativePeerEventListener.java index 9a2f55ee..15c5a95e 100644 --- a/core/src/main/java/org/bitcoinj/jni/NativePeerEventListener.java +++ b/core/src/main/java/org/bitcoinj/jni/NativePeerEventListener.java @@ -16,8 +16,7 @@ package org.bitcoinj.jni; -import org.bitcoinj.core.listeners.PeerConnectionEventListener; -import org.bitcoinj.core.listeners.PeerDataEventListener; +import org.bitcoinj.core.listeners.*; import org.bitcoinj.core.*; import javax.annotation.*; @@ -29,7 +28,7 @@ import java.util.Set; * this class using JNI on the native side, thus several instances of this can point to different actual * native implementations. */ -public class NativePeerEventListener implements PeerConnectionEventListener, PeerDataEventListener { +public class NativePeerEventListener implements PeerConnectionEventListener, PeerDataEventListener, OnTransactionBroadcastListener { public long ptr; @Override diff --git a/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java b/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java index e5f06beb..67b6eaf3 100644 --- a/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java +++ b/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java @@ -20,9 +20,7 @@ package org.bitcoinj.core; import com.google.common.collect.*; import com.google.common.net.*; import com.google.common.util.concurrent.*; -import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener; -import org.bitcoinj.core.listeners.AbstractPeerDataEventListener; -import org.bitcoinj.core.listeners.AbstractPeerEventListener; +import org.bitcoinj.core.listeners.*; import org.bitcoinj.net.discovery.*; import org.bitcoinj.testing.*; import org.bitcoinj.utils.*; @@ -349,7 +347,7 @@ public class PeerGroupTest extends TestWithPeerGroup { final Transaction[] event = new Transaction[1]; final TransactionConfidence[] confEvent = new TransactionConfidence[1]; - peerGroup.addDataEventListener(Threading.SAME_THREAD, new AbstractPeerDataEventListener() { + peerGroup.addOnTransactionBroadcastListener(Threading.SAME_THREAD, new OnTransactionBroadcastListener() { @Override public void onTransaction(Peer peer, Transaction t) { event[0] = t; diff --git a/core/src/test/java/org/bitcoinj/core/PeerTest.java b/core/src/test/java/org/bitcoinj/core/PeerTest.java index e7bfae6b..54a2f22d 100644 --- a/core/src/test/java/org/bitcoinj/core/PeerTest.java +++ b/core/src/test/java/org/bitcoinj/core/PeerTest.java @@ -17,10 +17,7 @@ package org.bitcoinj.core; import com.google.common.collect.*; -import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener; -import org.bitcoinj.core.listeners.AbstractPeerDataEventListener; -import org.bitcoinj.core.listeners.AbstractWalletEventListener; -import org.bitcoinj.core.listeners.PeerConnectionEventListener; +import org.bitcoinj.core.listeners.*; import org.bitcoinj.params.TestNet3Params; import org.bitcoinj.testing.FakeTxBuilder; import org.bitcoinj.testing.InboundMessageQueuer; @@ -549,7 +546,7 @@ public class PeerTest extends TestWithNetworkConnections { ECKey to = new ECKey(); final Transaction[] onTx = new Transaction[1]; - peer.addDataEventListener(Threading.SAME_THREAD, new AbstractPeerDataEventListener() { + peer.addOnTransactionBroadcastListener(Threading.SAME_THREAD, new OnTransactionBroadcastListener() { @Override public void onTransaction(Peer peer1, Transaction t) { onTx[0] = t; diff --git a/tools/src/main/java/org/bitcoinj/tools/WatchMempool.java b/tools/src/main/java/org/bitcoinj/tools/WatchMempool.java index 017bd2b9..d0aa3c2b 100644 --- a/tools/src/main/java/org/bitcoinj/tools/WatchMempool.java +++ b/tools/src/main/java/org/bitcoinj/tools/WatchMempool.java @@ -20,7 +20,7 @@ package org.bitcoinj.tools; import java.util.HashMap; import java.util.Map; -import org.bitcoinj.core.listeners.AbstractPeerDataEventListener; +import org.bitcoinj.core.listeners.*; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Peer; import org.bitcoinj.core.PeerGroup; @@ -49,7 +49,7 @@ public class WatchMempool { PeerGroup peerGroup = new PeerGroup(PARAMS); peerGroup.setMaxConnections(32); peerGroup.addPeerDiscovery(new DnsDiscovery(PARAMS)); - peerGroup.addDataEventListener(new AbstractPeerDataEventListener() { + peerGroup.addOnTransactionBroadcastListener(new OnTransactionBroadcastListener() { @Override public void onTransaction(Peer peer, Transaction tx) { Result result = DefaultRiskAnalysis.FACTORY.create(null, tx, NO_DEPS).analyze();