Peer: Prevent connecting to remote peers if required services are not supported.

This commit is contained in:
Andreas Schildbach 2020-03-04 17:15:07 +01:00
parent c967fda4d6
commit 57f53f038c
2 changed files with 19 additions and 11 deletions

View file

@ -68,6 +68,7 @@ public class Peer extends PeerSocketHandler {
private final NetworkParameters params; private final NetworkParameters params;
private final AbstractBlockChain blockChain; private final AbstractBlockChain blockChain;
private final long requiredServices;
private final Context context; private final Context context;
private final CopyOnWriteArrayList<ListenerRegistration<BlocksDownloadedEventListener>> blocksDownloadedEventListeners private final CopyOnWriteArrayList<ListenerRegistration<BlocksDownloadedEventListener>> blocksDownloadedEventListeners
@ -206,7 +207,7 @@ public class Peer extends PeerSocketHandler {
*/ */
public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress, public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress,
@Nullable AbstractBlockChain chain) { @Nullable AbstractBlockChain chain) {
this(params, ver, remoteAddress, chain, Integer.MAX_VALUE); this(params, ver, remoteAddress, chain, 0, Integer.MAX_VALUE);
} }
/** /**
@ -224,12 +225,13 @@ public class Peer extends PeerSocketHandler {
* used to keep track of which peers relayed transactions and offer more descriptive logging.</p> * used to keep track of which peers relayed transactions and offer more descriptive logging.</p>
*/ */
public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress, public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress,
@Nullable AbstractBlockChain chain, int downloadTxDependencyDepth) { @Nullable AbstractBlockChain chain, long requiredServices, int downloadTxDependencyDepth) {
super(params, remoteAddress); super(params, remoteAddress);
this.params = Preconditions.checkNotNull(params); this.params = Preconditions.checkNotNull(params);
this.versionMessage = Preconditions.checkNotNull(ver); this.versionMessage = Preconditions.checkNotNull(ver);
this.vDownloadTxDependencyDepth = chain != null ? downloadTxDependencyDepth : 0; this.vDownloadTxDependencyDepth = chain != null ? downloadTxDependencyDepth : 0;
this.blockChain = chain; // Allowed to be null. this.blockChain = chain; // Allowed to be null.
this.requiredServices = requiredServices;
this.vDownloadData = chain != null; this.vDownloadData = chain != null;
this.getDataFutures = new CopyOnWriteArrayList<>(); this.getDataFutures = new CopyOnWriteArrayList<>();
this.getAddrFutures = new LinkedList<>(); this.getAddrFutures = new LinkedList<>();
@ -520,33 +522,39 @@ public class Peer extends PeerSocketHandler {
future.set(m); future.set(m);
} }
private void processVersionMessage(VersionMessage m) throws ProtocolException { private void processVersionMessage(VersionMessage peerVersionMessage) throws ProtocolException {
if (vPeerVersionMessage != null) if (vPeerVersionMessage != null)
throw new ProtocolException("Got two version messages from peer"); throw new ProtocolException("Got two version messages from peer");
vPeerVersionMessage = m; vPeerVersionMessage = peerVersionMessage;
// Switch to the new protocol version. // Switch to the new protocol version.
log.info(toString()); log.info(toString());
// bitcoinj is a client mode implementation. That means there's not much point in us talking to other client // 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 // 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 // implementations claim to have a block chain in their services field but then report a height of zero, filter
// them out here. // them out here.
if (!vPeerVersionMessage.hasLimitedBlockChain() || if (!peerVersionMessage.hasLimitedBlockChain() ||
(!params.allowEmptyPeerChain() && vPeerVersionMessage.bestHeight == 0)) { (!params.allowEmptyPeerChain() && peerVersionMessage.bestHeight == 0)) {
// Shut down the channel gracefully. // Shut down the channel gracefully.
log.info("{}: Peer does not have at least a recent part of the block chain.", this); log.info("{}: Peer does not have at least a recent part of the block chain.", this);
close(); close();
return; return;
} }
if ((vPeerVersionMessage.localServices if ((peerVersionMessage.localServices & requiredServices) != requiredServices) {
& VersionMessage.NODE_BITCOIN_CASH) == VersionMessage.NODE_BITCOIN_CASH) { log.info("{}: Peer doesn't support these required services: {}", this,
VersionMessage.toStringServices(requiredServices & ~peerVersionMessage.localServices));
// Shut down the channel gracefully.
close();
return;
}
if ((peerVersionMessage.localServices & VersionMessage.NODE_BITCOIN_CASH) == VersionMessage.NODE_BITCOIN_CASH) {
log.info("{}: Peer follows an incompatible block chain.", this); log.info("{}: Peer follows an incompatible block chain.", this);
// Shut down the channel gracefully. // Shut down the channel gracefully.
close(); close();
return; return;
} }
if (vPeerVersionMessage.bestHeight < 0) if (peerVersionMessage.bestHeight < 0)
// In this case, it's a protocol violation. // In this case, it's a protocol violation.
throw new ProtocolException("Peer reports invalid best height: " + vPeerVersionMessage.bestHeight); throw new ProtocolException("Peer reports invalid best height: " + peerVersionMessage.bestHeight);
// Now it's our turn ... // Now it's our turn ...
// Send an ACK message stating we accept the peers protocol version. // Send an ACK message stating we accept the peers protocol version.
sendMessage(new VersionAck()); sendMessage(new VersionAck());

View file

@ -1382,7 +1382,7 @@ public class PeerGroup implements TransactionBroadcaster {
/** You can override this to customise the creation of {@link Peer} objects. */ /** You can override this to customise the creation of {@link Peer} objects. */
@GuardedBy("lock") @GuardedBy("lock")
protected Peer createPeer(PeerAddress address, VersionMessage ver) { protected Peer createPeer(PeerAddress address, VersionMessage ver) {
return new Peer(params, ver, address, chain, downloadTxDependencyDepth); return new Peer(params, ver, address, chain, requiredServices, downloadTxDependencyDepth);
} }
/** /**