3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-13 10:45:51 +00:00

Peer: Both halves of the version handshake need to be complete before the protocol can continue.

This commit is contained in:
Andreas Schildbach 2016-02-26 19:06:22 +01:00
parent b2d7b95450
commit 709e6f7562

View File

@ -153,11 +153,13 @@ public class Peer extends PeerSocketHandler {
private static final int PING_MOVING_AVERAGE_WINDOW = 20;
private volatile VersionMessage vPeerVersionMessage;
private boolean isAcked;
// A settable future which completes (with this) when the connection is open
private final SettableFuture<Peer> connectionOpenFuture = SettableFuture.create();
private final SettableFuture<Peer> versionHandshakeFuture = SettableFuture.create();
private final SettableFuture<Peer> outgoingVersionHandshakeFuture = SettableFuture.create();
private final SettableFuture<Peer> incomingVersionHandshakeFuture = SettableFuture.create();
private final ListenableFuture<List<Peer>> versionHandshakeFuture = Futures
.allAsList(outgoingVersionHandshakeFuture, incomingVersionHandshakeFuture);
/**
* <p>Construct a peer that reads/writes from the given block chain.</p>
@ -219,11 +221,17 @@ public class Peer extends PeerSocketHandler {
this.getDataFutures = new CopyOnWriteArrayList<GetDataRequest>();
this.getAddrFutures = new LinkedList<SettableFuture<AddressMessage>>();
this.fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds();
this.isAcked = false;
this.pendingPings = new CopyOnWriteArrayList<PendingPing>();
this.vMinProtocolVersion = params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.PONG);
this.wallets = new CopyOnWriteArrayList<Wallet>();
this.context = Context.get();
this.versionHandshakeFuture.addListener(new Runnable() {
@Override
public void run() {
versionHandshakeComplete();
}
}, Threading.SAME_THREAD);
}
/**
@ -426,7 +434,7 @@ public class Peer extends PeerSocketHandler {
return connectionOpenFuture;
}
public ListenableFuture<Peer> getVersionHandshakeFuture() {
public ListenableFuture<List<Peer>> getVersionHandshakeFuture() {
return versionHandshakeFuture;
}
@ -527,9 +535,6 @@ public class Peer extends PeerSocketHandler {
vPeerVersionMessage.localServices,
String.format(Locale.US, "%tF %tT", peerTime, peerTime),
vPeerVersionMessage.bestHeight);
// Now it's our turn ...
// Send an ACK message stating we accept the peers protocol version.
sendMessage(new VersionAck());
// bitcoinj is a client mode implementation. That means there's not much point in us talking to other client
// mode nodes because we can't download the data from them we need to find/verify transactions. Some bogus
// implementations claim to have a block chain in their services field but then report a height of zero, filter
@ -544,18 +549,27 @@ public class Peer extends PeerSocketHandler {
if (vPeerVersionMessage.bestHeight < 0)
// In this case, it's a protocol violation.
throw new ProtocolException("Peer reports invalid best height: " + vPeerVersionMessage.bestHeight);
versionHandshakeFuture.set(this);
// Now it's our turn ...
// Send an ACK message stating we accept the peers protocol version.
sendMessage(new VersionAck());
log.debug("{}: Incoming version handshake complete.", this);
incomingVersionHandshakeFuture.set(this);
}
private void processVersionAck(VersionAck m) throws ProtocolException {
if (vPeerVersionMessage == null) {
throw new ProtocolException("got a version ack before version");
}
if (isAcked) {
if (outgoingVersionHandshakeFuture.isDone()) {
throw new ProtocolException("got more than one version ack");
}
isAcked = true;
this.setTimeoutEnabled(false);
log.debug("{}: Outgoing version handshake complete.", this);
outgoingVersionHandshakeFuture.set(this);
}
private void versionHandshakeComplete() {
log.debug("{}: Handshake complete.", this);
setTimeoutEnabled(false);
for (final ListenerRegistration<PeerConnectedEventListener> registration : connectedEventListeners) {
registration.executor.execute(new Runnable() {
@Override