3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 07:12:17 +00:00

Use atomics for peers announced version and tracked chain height rather than locks.

Updates issue 310.
This commit is contained in:
Mike Hearn 2013-02-14 19:31:24 +01:00
parent 8dc9c9f27a
commit 067b7814e8

View File

@ -33,6 +33,8 @@ import java.net.InetSocketAddress;
import java.util.*; import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* A Peer handles the high level communication with a Bitcoin node. * A Peer handles the high level communication with a Bitcoin node.
@ -61,11 +63,11 @@ public class Peer {
private boolean downloadData = false; private boolean downloadData = false;
// The version data to announce to the other side of the connections we make: useful for setting our "user agent" // The version data to announce to the other side of the connections we make: useful for setting our "user agent"
// equivalent and other things. // equivalent and other things.
private VersionMessage versionMessage; private final VersionMessage versionMessage;
// How many block messages the peer has announced to us. Peers only announce blocks that attach to their best chain // How many block messages the peer has announced to us. Peers only announce blocks that attach to their best chain
// so we can use this to calculate the height of the peers chain, by adding it to the initial height in the version // so we can use this to calculate the height of the peers chain, by adding it to the initial height in the version
// message. This method can go wrong if the peer re-orgs onto a shorter (but harder) chain, however, this is rare. // message. This method can go wrong if the peer re-orgs onto a shorter (but harder) chain, however, this is rare.
private int blocksAnnounced; private AtomicInteger blocksAnnounced = new AtomicInteger();
// A class that tracks recent transactions that have been broadcast across the network, counts how many // A class that tracks recent transactions that have been broadcast across the network, counts how many
// peers announced them and updates the transaction confidence data. It is passed to each Peer. // peers announced them and updates the transaction confidence data. It is passed to each Peer.
// TODO: Make this final and unsynchronized. // TODO: Make this final and unsynchronized.
@ -109,7 +111,7 @@ public class Peer {
private static final int PING_MOVING_AVERAGE_WINDOW = 20; private static final int PING_MOVING_AVERAGE_WINDOW = 20;
private Channel channel; private Channel channel;
private VersionMessage peerVersionMessage; private AtomicReference<VersionMessage> peerVersionMessage = new AtomicReference<VersionMessage>();
private boolean isAcked; private boolean isAcked;
private PeerHandler handler; private PeerHandler handler;
@ -271,30 +273,26 @@ public class Peer {
} else if (m instanceof AlertMessage) { } else if (m instanceof AlertMessage) {
processAlert((AlertMessage) m); processAlert((AlertMessage) m);
} else if (m instanceof VersionMessage) { } else if (m instanceof VersionMessage) {
synchronized (Peer.this) { peerVersionMessage.set((VersionMessage) m);
peerVersionMessage = (VersionMessage)m;
}
EventListenerInvoker.invoke(lifecycleListeners, new EventListenerInvoker<PeerLifecycleListener>() { EventListenerInvoker.invoke(lifecycleListeners, new EventListenerInvoker<PeerLifecycleListener>() {
@Override @Override
public void invoke(PeerLifecycleListener listener) { public void invoke(PeerLifecycleListener listener) {
listener.onPeerConnected(Peer.this); listener.onPeerConnected(Peer.this);
} }
}); });
if (peerVersionMessage.clientVersion < minProtocolVersion) { if (getPeerVersionMessage().clientVersion < minProtocolVersion) {
log.warn("Connected to a peer speaking protocol version {} but need {}, closing", log.warn("Connected to a peer speaking protocol version {} but need {}, closing",
peerVersionMessage.clientVersion, minProtocolVersion); getPeerVersionMessage().clientVersion, minProtocolVersion);
e.getChannel().close(); e.getChannel().close();
} }
} else if (m instanceof VersionAck) { } else if (m instanceof VersionAck) {
synchronized (Peer.this) { if (getPeerVersionMessage() == null) {
if (peerVersionMessage == null) {
throw new ProtocolException("got a version ack before version"); throw new ProtocolException("got a version ack before version");
} }
if (isAcked) { if (isAcked) {
throw new ProtocolException("got more than one version ack"); throw new ProtocolException("got more than one version ack");
} }
isAcked = true; isAcked = true;
}
} else if (m instanceof Ping) { } else if (m instanceof Ping) {
if (((Ping) m).hasNonce()) if (((Ping) m).hasNonce())
sendMessage(new Pong(((Ping) m).getNonce())); sendMessage(new Pong(((Ping) m).getNonce()));
@ -738,7 +736,7 @@ public class Peer {
// 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.
final int blocksLeft = Math.max(0, (int)peerVersionMessage.bestHeight - blockChain.getBestChainHeight()); final int blocksLeft = Math.max(0, (int)getPeerVersionMessage().bestHeight - blockChain.getBestChainHeight());
EventListenerInvoker.invoke(eventListeners, new EventListenerInvoker<PeerEventListener>() { EventListenerInvoker.invoke(eventListeners, new EventListenerInvoker<PeerEventListener>() {
@Override @Override
public void invoke(PeerEventListener listener) { public void invoke(PeerEventListener listener) {
@ -770,10 +768,10 @@ public class Peer {
// chain, so count it. This way getBestChainHeight() can be accurate. // chain, so count it. This way getBestChainHeight() can be accurate.
if (downloadData) { if (downloadData) {
if (!blockChain.isOrphan(blocks.get(0).hash)) { if (!blockChain.isOrphan(blocks.get(0).hash)) {
blocksAnnounced++; blocksAnnounced.incrementAndGet();
} }
} else { } else {
blocksAnnounced++; blocksAnnounced.incrementAndGet();
} }
} }
@ -1188,25 +1186,21 @@ public class Peer {
return address; return address;
} }
/** /** Returns version data announced by the remote peer. */
* @return various version numbers claimed by peer. public VersionMessage getPeerVersionMessage() {
*/ return peerVersionMessage.get();
public synchronized VersionMessage getPeerVersionMessage() {
return peerVersionMessage;
} }
/** /** Returns version data we announce to our remote peers. */
* @return various version numbers we claim. public VersionMessage getVersionMessage() {
*/
public synchronized VersionMessage getVersionMessage() {
return versionMessage; return versionMessage;
} }
/** /**
* @return the height of the best chain as claimed by peer: sum of its ver announcement and blocks announced since. * @return the height of the best chain as claimed by peer: sum of its ver announcement and blocks announced since.
*/ */
public synchronized long getBestHeight() { public long getBestHeight() {
return peerVersionMessage.bestHeight + blocksAnnounced; return getPeerVersionMessage().bestHeight + blocksAnnounced.get();
} }
/** /**