org.bitcoinj.core.PeerGroup Maven / Gradle / Ivy
/*
* Copyright 2013 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.annotations.*;
import com.google.common.base.*;
import com.google.common.collect.*;
import com.google.common.net.*;
import com.google.common.primitives.*;
import com.google.common.util.concurrent.*;
import net.jcip.annotations.*;
import org.bitcoinj.core.listeners.*;
import org.bitcoinj.net.*;
import org.bitcoinj.net.discovery.*;
import org.bitcoinj.script.*;
import org.bitcoinj.utils.*;
import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.Wallet;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.bitcoinj.wallet.listeners.ScriptsChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletCoinsReceivedEventListener;
import org.slf4j.*;
import javax.annotation.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import okhttp3.OkHttpClient;
import static com.google.common.base.Preconditions.*;
/**
* Runs a set of connections to the P2P network, brings up connections to replace disconnected nodes and manages
* the interaction between them all. Most applications will want to use one of these.
*
* PeerGroup tries to maintain a constant number of connections to a set of distinct peers.
* Each peer runs a network listener in its own thread. When a connection is lost, a new peer
* will be tried after a delay as long as the number of connections less than the maximum.
*
* Connections are made to addresses from a provided list. When that list is exhausted,
* we start again from the head of the list.
*
* The PeerGroup can broadcast a transaction to the currently connected set of peers. It can
* also handle download of the blockchain from peers, restarting the process when peers die.
*
* A PeerGroup won't do anything until you call the {@link PeerGroup#start()} method
* which will block until peer discovery is completed and some outbound connections
* have been initiated (it will return before handshaking is done, however).
* You should call {@link PeerGroup#stop()} when finished. Note that not all methods
* of PeerGroup are safe to call from a UI thread as some may do network IO,
* but starting and stopping the service should be fine.
*/
public class PeerGroup implements TransactionBroadcaster {
private static final Logger log = LoggerFactory.getLogger(PeerGroup.class);
// All members in this class should be marked with final, volatile, @GuardedBy or a mix as appropriate to define
// their thread safety semantics. Volatile requires a Hungarian-style v prefix.
// By default we don't require any services because any peer will do.
private long requiredServices = 0;
/**
* The default number of connections to the p2p network the library will try to build. This is set to 12 empirically.
* It used to be 4, but because we divide the connection pool in two for broadcasting transactions, that meant we
* were only sending transactions to two peers and sometimes this wasn't reliable enough: transactions wouldn't
* get through.
*/
public static final int DEFAULT_CONNECTIONS = 12;
private volatile int vMaxPeersToDiscoverCount = 100;
private static final long DEFAULT_PEER_DISCOVERY_TIMEOUT_MILLIS = 5000;
private volatile long vPeerDiscoveryTimeoutMillis = DEFAULT_PEER_DISCOVERY_TIMEOUT_MILLIS;
protected final ReentrantLock lock = Threading.lock("peergroup");
protected final NetworkParameters params;
@Nullable protected final AbstractBlockChain chain;
// This executor is used to queue up jobs: it's used when we don't want to use locks for mutual exclusion,
// typically because the job might call in to user provided code that needs/wants the freedom to use the API
// however it wants, or because a job needs to be ordered relative to other jobs like that.
protected final ListeningScheduledExecutorService executor;
// Whether the peer group is currently running. Once shut down it cannot be restarted.
private volatile boolean vRunning;
// Whether the peer group has been started or not. An unstarted PG does not try to access the network.
private volatile boolean vUsedUp;
// Addresses to try to connect to, excluding active peers.
@GuardedBy("lock") private final PriorityQueue inactives;
@GuardedBy("lock") private final Map backoffMap;
// Currently active peers. This is an ordered list rather than a set to make unit tests predictable.
private final CopyOnWriteArrayList peers;
// Currently connecting peers.
private final CopyOnWriteArrayList pendingPeers;
private final ClientConnectionManager channels;
// The peer that has been selected for the purposes of downloading announced data.
@GuardedBy("lock") private Peer downloadPeer;
// Callback for events related to chain download.
@Nullable @GuardedBy("lock") private PeerDataEventListener downloadListener;
private final CopyOnWriteArrayList> peersBlocksDownloadedEventListeners
= new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList> peersChainDownloadStartedEventListeners
= new CopyOnWriteArrayList<>();
/** Callbacks for events related to peers connecting */
protected final CopyOnWriteArrayList> peerConnectedEventListeners
= new CopyOnWriteArrayList<>();
/** Callbacks for events related to peer connection/disconnection */
protected final CopyOnWriteArrayList> peerDiscoveredEventListeners
= new CopyOnWriteArrayList<>();
/** Callbacks for events related to peers disconnecting */
protected final CopyOnWriteArrayList> peerDisconnectedEventListeners
= new CopyOnWriteArrayList<>();
/** Callbacks for events related to peer data being received */
private final CopyOnWriteArrayList> peerGetDataEventListeners
= new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList> peersPreMessageReceivedEventListeners
= new CopyOnWriteArrayList<>();
protected final CopyOnWriteArrayList> peersTransactionBroadastEventListeners
= new CopyOnWriteArrayList<>();
// Peer discovery sources, will be polled occasionally if there aren't enough inactives.
private final CopyOnWriteArraySet peerDiscoverers;
// The version message to use for new connections.
@GuardedBy("lock") private VersionMessage versionMessage;
// Maximum depth up to which pending transaction dependencies are downloaded, or 0 for disabled.
@GuardedBy("lock") private int downloadTxDependencyDepth;
// How many connections we want to have open at the current time. If we lose connections, we'll try opening more
// until we reach this count.
@GuardedBy("lock") private int maxConnections;
// Minimum protocol version we will allow ourselves to connect to: require Bloom filtering.
private volatile int vMinRequiredProtocolVersion;
/** How many milliseconds to wait after receiving a pong before sending another ping. */
public static final long DEFAULT_PING_INTERVAL_MSEC = 2000;
@GuardedBy("lock") private long pingIntervalMsec = DEFAULT_PING_INTERVAL_MSEC;
@GuardedBy("lock") private boolean useLocalhostPeerWhenPossible = true;
@GuardedBy("lock") private boolean ipv6Unreachable = false;
@GuardedBy("lock") private long fastCatchupTimeSecs;
private final CopyOnWriteArrayList wallets;
private final CopyOnWriteArrayList peerFilterProviders;
// This event listener is added to every peer. It's here so when we announce transactions via an "inv", every
// peer can fetch them.
private final PeerListener peerListener = new PeerListener();
private int minBroadcastConnections = 0;
private final ScriptsChangeEventListener walletScriptEventListener = new ScriptsChangeEventListener() {
@Override public void onScriptsChanged(Wallet wallet, List