@Override public void connectionOpened() { // Announce ourselves. This has to come first to connect to clients beyond v0.3.20.2 which wait to hear // from us until they send their version message back. PeerAddress address = getAddress(); log.info("Announcing to {} as: {}", address == null ? "Peer" : address.toSocketAddress(), versionMessage.subVer); sendMessage(versionMessage); connectionOpenFuture.set(this); // When connecting, the remote peer sends us a version message with various bits of // useful data in it. We need to know the peer protocol version before we can talk to it. }
/** * Returns most commonly reported chain height from the given list of {@link Peer}s. * If multiple heights are tied, the highest is returned. If no peers are connected, returns zero. */ public static int getMostCommonChainHeight(final List<Peer> peers) { if (peers.isEmpty()) return 0; List<Integer> heights = new ArrayList<>(peers.size()); for (Peer peer : peers) heights.add((int) peer.getBestHeight()); return Utils.maxOfMostFreq(heights); }
/** * The minimum P2P protocol version that is accepted. If the peer speaks a protocol version lower than this, it * will be disconnected. * @return true if the peer was disconnected as a result */ public boolean setMinProtocolVersion(int minProtocolVersion) { this.vMinProtocolVersion = minProtocolVersion; VersionMessage ver = getPeerVersionMessage(); if (ver != null && ver.clientVersion < minProtocolVersion) { log.warn("{}: Disconnecting due to new min protocol version {}, got: {}", this, minProtocolVersion, ver.clientVersion); close(); return true; } return false; }
/** * Register a data event listener against a single peer (i.e. for blockchain * download). Handling registration/deregistration on peer death/add is * outside the scope of these methods. */ private static void addDataEventListenerToPeer(Executor executor, Peer peer, PeerDataEventListener downloadListener) { peer.addBlocksDownloadedEventListener(executor, downloadListener); peer.addChainDownloadStartedEventListener(executor, downloadListener); peer.addGetDataEventListener(executor, downloadListener); peer.addPreMessageReceivedEventListener(executor, downloadListener); }
/** Deprecated: use the more specific event handler methods instead */ @Deprecated @SuppressWarnings("deprecation") public void addEventListener(AbstractPeerEventListener listener) { addBlocksDownloadedEventListener(Threading.USER_THREAD, listener); addChainDownloadStartedEventListener(Threading.USER_THREAD, listener); addConnectedEventListener(Threading.USER_THREAD, listener); addDisconnectedEventListener(Threading.USER_THREAD, listener); addGetDataEventListener(Threading.USER_THREAD, listener); addOnTransactionBroadcastListener(Threading.USER_THREAD, listener); addPreMessageReceivedEventListener(Threading.USER_THREAD, listener); }
ver.appendToSubVer("BlockAcceptanceComparisonTool", "1.1", null); ver.localServices = VersionMessage.NODE_NETWORK; final Peer bitcoind = new Peer(params, ver, new BlockChain(params, new MemoryBlockStore(params)), new PeerAddress(params, InetAddress.getLocalHost())); Preconditions.checkState(bitcoind.getVersionMessage().hasBlockChain()); final AtomicInteger unexpectedInvs = new AtomicInteger(0); final SettableFuture<Void> connectedFuture = SettableFuture.create(); bitcoind.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() { @Override public void onPeerConnected(Peer peer, int peerCount) { bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() { @Override public void onPeerDisconnected(Peer peer, int peerCount) { bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, new PreMessageReceivedEventListener() { @Override public Message onPreMessageReceived(Peer peer, Message m) { InventoryMessage message = new InventoryMessage(params); message.addBlock(nextBlock); bitcoind.sendMessage(message); log.info("Sent inv with block " + nextBlock.getHashAsString()); if (blocksPendingSend.contains(nextBlock.getHash())) { bitcoind.sendMessage(nextBlock); log.info("Sent full block " + nextBlock.getHashAsString()); bitcoind.sendMessage(new GetHeadersMessage(params, locator, hashTo)); bitcoind.ping().get();
lock.lock(); try { log.debug("{}: Received tx {}", getAddress(), tx.getHashAsString()); confidence.setSource(TransactionConfidence.Source.NETWORK); pendingTxDownloads.remove(confidence); if (maybeHandleRequestedData(tx)) { return; if (!currentFilteredBlock.provideTransaction(tx)) { endFilteredBlock(currentFilteredBlock); currentFilteredBlock = null; Futures.addCallback(downloadDependencies(tx), new FutureCallback<List<Transaction>>() { @Override public void onSuccess(List<Transaction> dependencies) {
@Override public void run() { try { if (getPingIntervalMsec() <= 0) { ListenableScheduledFuture<?> task = vPingTask; if (task != null) { task.cancel(false); vPingTask = null; } return; // Disabled. } for (Peer peer : getConnectedPeers()) { if (peer.getPeerVersionMessage().clientVersion < params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.PONG)) continue; peer.ping(); } } catch (Throwable e) { log.error("Exception in ping loop", e); // The executor swallows exceptions :( } } }, getPingIntervalMsec(), getPingIntervalMsec(), TimeUnit.MILLISECONDS);
@Override public void onSuccess(List<Transaction> dependencies) { try { log.info("{}: Dependency download complete!", getAddress()); wallet.receivePending(tx, dependencies); } catch (VerificationException e) { log.error("{}: Wallet failed to process pending transaction {}", getAddress(), tx.getHash()); log.error("Error was: ", e); // Not much more we can do at this point. } }
@Override public void serialize(Peer value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { jgen.writeStartObject(); jgen.writeStringField("socketAddress", value.getAddress().toSocketAddress().toString()); jgen.writeNumberField("remoteVersion", value.getPeerVersionMessage().clientVersion); jgen.writeNumberField("bestHeight", value.getPeerVersionMessage().bestHeight); jgen.writeEndObject(); } }
close(); return; log.info("{}: Peer follows an incompatible block chain.", this); close(); return; sendMessage(new VersionAck()); log.debug("{}: Incoming version handshake complete.", this); incomingVersionHandshakeFuture.set(this);
for (final InetAddress addr : addrs) { InetSocketAddress address = new InetSocketAddress(addr, params.getPort()); final Peer peer = new Peer(params, new VersionMessage(params, 0), null, new PeerAddress(address)); final SettableFuture<Void> future = SettableFuture.create(); peer.addConnectedEventListener(new PeerConnectedEventListener() { @Override public void onPeerConnected(Peer p, int peerCount) { peer.addDisconnectedEventListener(new PeerDisconnectedEventListener() { @Override public void onPeerDisconnected(Peer p, int peerCount) {
private void versionHandshakeComplete() { log.debug("{}: Handshake complete.", this); setTimeoutEnabled(false); for (final ListenerRegistration<PeerConnectedEventListener> registration : connectedEventListeners) { registration.executor.execute(new Runnable() { @Override public void run() { registration.listener.onPeerConnected(Peer.this, 1); } }); } // We check min version after onPeerConnected as channel.close() will // call onPeerDisconnected, and we should probably call onPeerConnected first. final int version = vMinProtocolVersion; if (vPeerVersionMessage.clientVersion < version) { log.warn("Connected to a peer speaking protocol version {} but need {}, closing", vPeerVersionMessage.clientVersion, version); close(); } }
/** * Returns an array list of peers that implement the given protocol version or better. */ public List<Peer> findPeersOfAtLeastVersion(long protocolVersion) { lock.lock(); try { ArrayList<Peer> results = new ArrayList<Peer>(peers.size()); for (Peer peer : peers) if (peer.getPeerVersionMessage().clientVersion >= protocolVersion) results.add(peer); return results; } finally { lock.unlock(); } }
/** * Ping all connected peers to see if there is an active network connection * * @return true is two or more peers respond to the ping */ public boolean pingPeers() { List<Peer> connectedPeers = peerGroup.getConnectedPeers(); int numberOfSuccessfulPings = 0; if (connectedPeers != null) { for (Peer peer : connectedPeers) { log.debug("Ping: {}", peer.getAddress().toString()); try { ListenableFuture<Long> result = peer.ping(); result.get(4, TimeUnit.SECONDS); numberOfSuccessfulPings++; if (numberOfSuccessfulPings >= NUMBER_OF_PEERS_TO_PING) { break; } } catch (ProtocolException | InterruptedException | ExecutionException | TimeoutException e) { log.warn("Peer '" + peer.getAddress().toString() + "' failed ping test. Message was " + e.getMessage()); } } } return numberOfSuccessfulPings >= 2; }
/** * Sends the peer a ping message and returns a future that will be invoked when the pong is received back. * The future provides a number which is the number of milliseconds elapsed between the ping and the pong. * Once the pong is received the value returned by {@link org.bitcoinj.core.Peer#getLastPingTime()} is * updated. * @throws ProtocolException if the peer version is too low to support measurable pings. */ public ListenableFuture<Long> ping() throws ProtocolException { return ping((long) (Math.random() * Long.MAX_VALUE)); }
@Test public void testAddConnectedEventListener() throws Exception { connect(); PeerConnectedEventListener listener = new AbstractPeerConnectionEventListener() { }; assertFalse(peer.removeConnectedEventListener(listener)); peer.addConnectedEventListener(listener); assertTrue(peer.removeConnectedEventListener(listener)); assertFalse(peer.removeConnectedEventListener(listener)); }
@Test public void testAddDisconnectedEventListener() throws Exception { connect(); PeerDisconnectedEventListener listener = new AbstractPeerConnectionEventListener() { }; assertFalse(peer.removeDisconnectedEventListener(listener)); peer.addDisconnectedEventListener(listener); assertTrue(peer.removeDisconnectedEventListener(listener)); assertFalse(peer.removeDisconnectedEventListener(listener)); }
/** * <p>Adds a listener that will be notified on the given executor when * new peers are connected to.</p> */ public void addConnectedEventListener(Executor executor, PeerConnectedEventListener listener) { peerConnectedEventListeners.add(new ListenerRegistration<>(checkNotNull(listener), executor)); for (Peer peer : getConnectedPeers()) peer.addConnectedEventListener(executor, listener); for (Peer peer : getPendingPeers()) peer.addConnectedEventListener(executor, listener); }