From 57f53f038c4e1383c5b8a76b74bd6212177f71ed Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Wed, 4 Mar 2020 17:15:07 +0100 Subject: [PATCH] Peer: Prevent connecting to remote peers if required services are not supported. --- .../src/main/java/org/bitcoinj/core/Peer.java | 28 ++++++++++++------- .../java/org/bitcoinj/core/PeerGroup.java | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java index 06d25f1b2..2ed96f2df 100644 --- a/core/src/main/java/org/bitcoinj/core/Peer.java +++ b/core/src/main/java/org/bitcoinj/core/Peer.java @@ -68,6 +68,7 @@ public class Peer extends PeerSocketHandler { private final NetworkParameters params; private final AbstractBlockChain blockChain; + private final long requiredServices; private final Context context; private final CopyOnWriteArrayList> blocksDownloadedEventListeners @@ -206,7 +207,7 @@ public class Peer extends PeerSocketHandler { */ public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress, @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.

*/ public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress, - @Nullable AbstractBlockChain chain, int downloadTxDependencyDepth) { + @Nullable AbstractBlockChain chain, long requiredServices, int downloadTxDependencyDepth) { super(params, remoteAddress); this.params = Preconditions.checkNotNull(params); this.versionMessage = Preconditions.checkNotNull(ver); this.vDownloadTxDependencyDepth = chain != null ? downloadTxDependencyDepth : 0; this.blockChain = chain; // Allowed to be null. + this.requiredServices = requiredServices; this.vDownloadData = chain != null; this.getDataFutures = new CopyOnWriteArrayList<>(); this.getAddrFutures = new LinkedList<>(); @@ -520,33 +522,39 @@ public class Peer extends PeerSocketHandler { future.set(m); } - private void processVersionMessage(VersionMessage m) throws ProtocolException { + private void processVersionMessage(VersionMessage peerVersionMessage) throws ProtocolException { if (vPeerVersionMessage != null) throw new ProtocolException("Got two version messages from peer"); - vPeerVersionMessage = m; + vPeerVersionMessage = peerVersionMessage; // Switch to the new protocol version. log.info(toString()); // 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 // them out here. - if (!vPeerVersionMessage.hasLimitedBlockChain() || - (!params.allowEmptyPeerChain() && vPeerVersionMessage.bestHeight == 0)) { + if (!peerVersionMessage.hasLimitedBlockChain() || + (!params.allowEmptyPeerChain() && peerVersionMessage.bestHeight == 0)) { // Shut down the channel gracefully. log.info("{}: Peer does not have at least a recent part of the block chain.", this); close(); return; } - if ((vPeerVersionMessage.localServices - & VersionMessage.NODE_BITCOIN_CASH) == VersionMessage.NODE_BITCOIN_CASH) { + if ((peerVersionMessage.localServices & requiredServices) != requiredServices) { + 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); // Shut down the channel gracefully. close(); return; } - if (vPeerVersionMessage.bestHeight < 0) + if (peerVersionMessage.bestHeight < 0) // 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 ... // Send an ACK message stating we accept the peers protocol version. sendMessage(new VersionAck()); diff --git a/core/src/main/java/org/bitcoinj/core/PeerGroup.java b/core/src/main/java/org/bitcoinj/core/PeerGroup.java index 23d0ac816..25625dbbb 100644 --- a/core/src/main/java/org/bitcoinj/core/PeerGroup.java +++ b/core/src/main/java/org/bitcoinj/core/PeerGroup.java @@ -1382,7 +1382,7 @@ public class PeerGroup implements TransactionBroadcaster { /** You can override this to customise the creation of {@link Peer} objects. */ @GuardedBy("lock") protected Peer createPeer(PeerAddress address, VersionMessage ver) { - return new Peer(params, ver, address, chain, downloadTxDependencyDepth); + return new Peer(params, ver, address, chain, requiredServices, downloadTxDependencyDepth); } /**