Ensure peer.eventListeners is always accessed under the peer lock, and switch to EventListenerInvoker in most places so listeners can remove themselves.

Resolves issue 210.
This commit is contained in:
Mike Hearn
2012-07-22 02:00:15 +02:00
parent 915a878a13
commit abc9f09db3

View File

@@ -188,16 +188,17 @@ public class Peer {
/** Handle incoming Bitcoin messages */ /** Handle incoming Bitcoin messages */
@Override @Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
throws Exception {
Message m = (Message)e.getMessage(); Message m = (Message)e.getMessage();
// Allow event listeners to filter the message stream. Listeners are allowed to drop messages by // Allow event listeners to filter the message stream. Listeners are allowed to drop messages by
// returning null. // returning null.
for (PeerEventListener listener : eventListeners) { synchronized (Peer.this) {
synchronized (listener) { for (PeerEventListener listener : eventListeners) {
m = listener.onPreMessageReceived(Peer.this, m); synchronized (listener) {
if (m == null) break; m = listener.onPreMessageReceived(Peer.this, m);
if (m == null) break;
}
} }
} }
@@ -328,17 +329,19 @@ public class Peer {
} }
} }
private void processTransaction(Transaction tx) { private synchronized void processTransaction(Transaction tx) {
log.info("Received broadcast tx {}", tx.getHashAsString()); log.info("Received broadcast tx {}", tx.getHashAsString());
if (memoryPool != null) { if (memoryPool != null) {
// We may get back a different transaction object. // We may get back a different transaction object.
tx = memoryPool.seen(tx, getAddress()); tx = memoryPool.seen(tx, getAddress());
} }
for (PeerEventListener listener : eventListeners) { final Transaction ftx = tx;
synchronized (listener) { EventListenerInvoker.invoke(eventListeners, new EventListenerInvoker<PeerEventListener>() {
listener.onTransaction(this, tx); @Override
public void invoke(PeerEventListener listener) {
listener.onTransaction(Peer.this, ftx);
} }
} });
} }
private void processBlock(Block m) throws IOException { private void processBlock(Block m) throws IOException {
@@ -394,7 +397,7 @@ public class Peer {
} }
} }
private void invokeOnBlocksDownloaded(final Block m) { private synchronized void invokeOnBlocksDownloaded(final Block m) {
// It is possible for the peer block height difference to be negative when blocks have been solved and broadcast // It is possible for the peer block height difference to be negative when blocks have been solved and broadcast
// since the time we first connected to the peer. However, it's weird and unexpected to receive a callback // since the time we first connected to the peer. However, it's weird and unexpected to receive a callback
// with negative "blocks left" in this case, so we clamp to zero so the API user doesn't have to think about it. // with negative "blocks left" in this case, so we clamp to zero so the API user doesn't have to think about it.
@@ -705,16 +708,17 @@ public class Peer {
* Starts an asynchronous download of the block chain. The chain download is deemed to be complete once we've * Starts an asynchronous download of the block chain. The chain download is deemed to be complete once we've
* downloaded the same number of blocks that the peer advertised having in its version handshake message. * downloaded the same number of blocks that the peer advertised having in its version handshake message.
*/ */
public void startBlockChainDownload() throws IOException { public synchronized void startBlockChainDownload() throws IOException {
setDownloadData(true); setDownloadData(true);
// TODO: peer might still have blocks that we don't have, and even have a heavier // TODO: peer might still have blocks that we don't have, and even have a heavier
// chain even if the chain block count is lower. // chain even if the chain block count is lower.
if (getPeerBlockHeightDifference() >= 0) { if (getPeerBlockHeightDifference() >= 0) {
for (PeerEventListener listener : eventListeners) { EventListenerInvoker.invoke(eventListeners, new EventListenerInvoker<PeerEventListener>() {
synchronized (listener) { @Override
listener.onChainDownloadStarted(this, getPeerBlockHeightDifference()); public void invoke(PeerEventListener listener) {
listener.onChainDownloadStarted(Peer.this, getPeerBlockHeightDifference());
} }
} });
// When we just want as many blocks as possible, we can set the target hash to zero. // When we just want as many blocks as possible, we can set the target hash to zero.
blockChainDownload(Sha256Hash.ZERO_HASH); blockChainDownload(Sha256Hash.ZERO_HASH);