public class PeerGroup extends AbstractExecutionThreadService implements TransactionBroadcaster
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.
PeerGroup implements the Service
interface. This means before it will do anything,
you must call the Service.start()
method (which returns
a future) or Service.startAndWait()
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 Service.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.
Modifier and Type | Class and Description |
---|---|
static class |
PeerGroup.FilterRecalculateMode |
Service.Listener, Service.State
Modifier and Type | Field and Description |
---|---|
static double |
DEFAULT_BLOOM_FILTER_FP_RATE
A reasonable default for the bloom filter false positive rate on mainnet.
|
static int |
DEFAULT_CONNECT_TIMEOUT_MILLIS
The default timeout between when a connection attempt begins and version message exchange completes
|
static long |
DEFAULT_PING_INTERVAL_MSEC
How many milliseconds to wait after receiving a pong before sending another ping.
|
protected ReentrantLock |
lock |
static double |
MAX_FP_RATE_INCREASE
Maximum increase in FP rate before forced refresh of the bloom filter
|
Constructor and Description |
---|
PeerGroup(NetworkParameters params)
Creates a PeerGroup with the given parameters.
|
PeerGroup(NetworkParameters params,
AbstractBlockChain chain)
Creates a PeerGroup for the given network and chain.
|
PeerGroup(NetworkParameters params,
AbstractBlockChain chain,
ClientConnectionManager connectionManager)
Creates a new PeerGroup allowing you to specify the
ClientConnectionManager which is used to create new
connections and keep track of existing ones. |
Modifier and Type | Method and Description |
---|---|
void |
addAddress(InetAddress address)
Convenience method for addAddress(new PeerAddress(address, params.port));
|
void |
addAddress(PeerAddress peerAddress)
Add an address to the list of potential peers to connect to.
|
void |
addEventListener(PeerEventListener listener)
Same as
addEventListener(PeerEventListener, java.util.concurrent.Executor) but defaults
to running on the user thread. |
void |
addEventListener(PeerEventListener listener,
Executor executor)
Adds a listener that will be notified on the given executor when:
|
void |
addPeerDiscovery(PeerDiscovery peerDiscovery)
Add addresses from a discovery source to the list of potential peers to connect to.
|
void |
addPeerFilterProvider(PeerFilterProvider provider)
Link the given PeerFilterProvider to this PeerGroup.
|
void |
addWallet(Wallet wallet)
Link the given wallet to this PeerGroup.
|
ListenableFuture<Transaction> |
broadcastTransaction(Transaction tx)
Calls
broadcastTransaction(Transaction,int) with getMinBroadcastConnections() as the number
of connections to wait for before commencing broadcast. |
ListenableFuture<Transaction> |
broadcastTransaction(Transaction tx,
int minConnections)
Given a transaction, sends it un-announced to one peer and then waits for it to be received back from other
peers.
|
void |
clearEventListeners()
Removes all event listeners simultaneously.
|
Peer |
connectTo(InetSocketAddress address)
Connect to a peer by creating a channel to the destination address.
|
protected Peer |
connectTo(PeerAddress address,
boolean incrementMaxConnections,
int connectTimeoutMillis)
Creates a version message to send, constructs a Peer object and attempts to connect it.
|
protected void |
connectToAnyPeer()
Picks a peer from discovery and connects to it.
|
Peer |
connectToLocalHost()
Helper for forcing a connection to localhost.
|
protected void |
discoverPeers() |
void |
downloadBlockChain()
Download the blockchain from peers.
|
List<Peer> |
findPeersOfAtLeastVersion(long protocolVersion)
Returns a mutable array list of peers that implement the given protocol version or better.
|
List<Peer> |
getConnectedPeers()
Returns a newly allocated list containing the currently connected peers.
|
Peer |
getDownloadPeer()
Returns the currently selected download peer.
|
long |
getFastCatchupTimeSecs()
Returns the current fast catchup time.
|
int |
getMaxConnections()
The maximum number of connections that we will create to peers.
|
MemoryPool |
getMemoryPool()
Returns the
MemoryPool created by this peer group to synchronize its peers. |
int |
getMinBroadcastConnections()
Returns the number of connections that are required before transactions will be broadcast.
|
int |
getMinRequiredProtocolVersion()
The minimum protocol version required: defaults to the version required for Bloom filtering.
|
int |
getMostCommonChainHeight()
Returns our peers most commonly reported chain height.
|
static int |
getMostCommonChainHeight(List<Peer> peers)
Returns most commonly reported chain height from the given list of
Peer s. |
List<Peer> |
getPendingPeers()
Returns a list containing Peers that did not complete connection yet.
|
long |
getPingIntervalMsec()
Returns the period between pings for an individual peer.
|
com.subgraph.orchid.TorClient |
getTorClient()
Returns the
TorClient object for this peer group, if Tor is in use, null otherwise. |
boolean |
getUseLocalhostPeerWhenPossible()
|
VersionMessage |
getVersionMessage()
Returns the version message provided by setVersionMessage or a default if none was given.
|
protected void |
handleNewPeer(Peer peer) |
protected void |
handlePeerDeath(Peer peer) |
static PeerGroup |
newWithTor(NetworkParameters params,
AbstractBlockChain chain,
com.subgraph.orchid.TorClient torClient)
Creates a PeerGroup that accesses the network via the Tor network.
|
int |
numConnectedPeers()
Returns the number of currently connected peers.
|
void |
recalculateFastCatchupAndFilter(PeerGroup.FilterRecalculateMode mode)
Recalculates the bloom filter given to peers as well as the timestamp after which full blocks are downloaded
(instead of only headers).
|
boolean |
removeEventListener(PeerEventListener listener)
The given event listener will no longer be called with events.
|
void |
removeWallet(Wallet wallet)
Unlinks the given wallet so it no longer receives broadcast transactions or has its transactions announced.
|
protected void |
run() |
protected Peer |
selectDownloadPeer(List<Peer> peers)
Given a list of Peers, return a Peer to be used as the download peer.
|
void |
setBloomFilterFalsePositiveRate(double bloomFilterFPRate)
Sets the false positive rate of bloom filters given to peers.
|
void |
setConnectTimeoutMillis(int connectTimeoutMillis)
Sets the timeout between when a connection attempt to a peer begins and when the version message exchange
completes.
|
void |
setDownloadTxDependencies(boolean downloadTxDependencies)
Switch for enabling download of pending transaction dependencies.
|
void |
setFastCatchupTimeSecs(long secondsSinceEpoch)
Tells the PeerGroup to download only block headers before a certain time and bodies after that.
|
void |
setMaxConnections(int maxConnections)
Adjusts the desired number of connections that we will create to peers.
|
void |
setMinBroadcastConnections(int value)
|
void |
setMinRequiredProtocolVersion(int minRequiredProtocolVersion)
If a peer is connected to that claims to speak a protocol version lower than the given version, it will
be disconnected and another one will be tried instead.
|
void |
setPingIntervalMsec(long pingIntervalMsec)
Sets the period between pings for an individual peer.
|
void |
setUseLocalhostPeerWhenPossible(boolean useLocalhostPeerWhenPossible)
When true (the default), PeerGroup will attempt to connect to a Bitcoin node running on localhost before
attempting to use the P2P network.
|
void |
setUserAgent(String name,
String version)
Sets information that identifies this software to remote nodes.
|
void |
setUserAgent(String name,
String version,
String comments)
Sets information that identifies this software to remote nodes.
|
void |
setVersionMessage(VersionMessage ver)
Sets the
VersionMessage that will be announced on newly created connections. |
protected void |
shutDown() |
void |
startBlockChainDownload(PeerEventListener listener)
Start downloading the blockchain from the first available peer.
|
protected void |
startUp() |
protected void |
triggerShutdown() |
ListenableFuture<List<Peer>> |
waitForPeers(int numPeers)
Returns a future that is triggered when the number of connected peers is equal to the given number of
peers.
|
ListenableFuture<List<Peer>> |
waitForPeersOfVersion(int numPeers,
long protocolVersion)
Returns a future that is triggered when there are at least the requested number of connected peers that support
the given protocol version or higher.
|
addListener, awaitRunning, awaitRunning, awaitTerminated, awaitTerminated, executor, failureCause, isRunning, serviceName, start, startAndWait, startAsync, state, stop, stopAndWait, stopAsync, toString
protected final ReentrantLock lock
public static final long DEFAULT_PING_INTERVAL_MSEC
public static final double DEFAULT_BLOOM_FILTER_FP_RATE
A reasonable default for the bloom filter false positive rate on mainnet. FP rates are values between 0.0 and 1.0 where 1.0 is "all transactions" i.e. 100%.
Users for which low data usage is of utmost concern, 0.0001 may be better, for users to whom anonymity is of utmost concern, 0.001 (0.1%) should provide very good privacy.
public static final double MAX_FP_RATE_INCREASE
public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS
public PeerGroup(NetworkParameters params)
params
- Network parameterspublic PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain)
public PeerGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager)
ClientConnectionManager
which is used to create new
connections and keep track of existing ones.public static PeerGroup newWithTor(NetworkParameters params, @Nullable AbstractBlockChain chain, com.subgraph.orchid.TorClient torClient) throws TimeoutException
Creates a PeerGroup that accesses the network via the Tor network. The provided TorClient is used so you can preconfigure it beforehand. It should not have been already started. You can just use "new TorClient()" if you don't have any particular configuration requirements.
Peer discovery is automatically configured to use DNS seeds resolved via a random selection of exit nodes. If running on the Oracle JDK the unlimited strength jurisdiction checks will also be overridden, as they no longer apply anyway and can cause startup failures due to the requirement for AES-256.
The user does not need any additional software for this: it's all pure Java. As of April 2014 this mode is experimental.
TimeoutException
- if Tor fails to start within 20 seconds.public void setMaxConnections(int maxConnections)
public void setDownloadTxDependencies(boolean downloadTxDependencies)
public int getMaxConnections()
public void setVersionMessage(VersionMessage ver)
VersionMessage
that will be announced on newly created connections. A version message is
primarily interesting because it lets you customize the "subVer" field which is used a bit like the User-Agent
field from HTTP. It means your client tells the other side what it is, see
BIP 14.
The VersionMessage you provide is copied and the best chain height/time filled in for each new connection,
therefore you don't have to worry about setting that. The provided object is really more of a template.public VersionMessage getVersionMessage()
public void setUserAgent(String name, String version, @Nullable String comments)
VersionMessage
, calling VersionMessage.appendToSubVer(String, String, String)
on it,
and then calling setVersionMessage(VersionMessage)
on the result of that. See the docs for
VersionMessage.appendToSubVer(String, String, String)
for information on what the fields should contain.public void setUserAgent(String name, String version)
VersionMessage
, calling VersionMessage.appendToSubVer(String, String, String)
on it,
and then calling setVersionMessage(VersionMessage)
on the result of that. See the docs for
VersionMessage.appendToSubVer(String, String, String)
for information on what the fields should contain.public void addEventListener(PeerEventListener listener, Executor executor)
Adds a listener that will be notified on the given executor when:
public void addEventListener(PeerEventListener listener)
addEventListener(PeerEventListener, java.util.concurrent.Executor)
but defaults
to running on the user thread.public boolean removeEventListener(PeerEventListener listener)
public void clearEventListeners()
public List<Peer> getConnectedPeers()
public List<Peer> getPendingPeers()
public void addAddress(PeerAddress peerAddress)
peerAddress
- IP/port to use.public void addAddress(InetAddress address)
public void addPeerDiscovery(PeerDiscovery peerDiscovery)
protected void discoverPeers() throws PeerDiscoveryException
PeerDiscoveryException
protected void run() throws Exception
run
in class AbstractExecutionThreadService
Exception
protected void connectToAnyPeer() throws PeerDiscoveryException
PeerDiscoveryException
protected void startUp() throws Exception
startUp
in class AbstractExecutionThreadService
Exception
protected void shutDown() throws Exception
shutDown
in class AbstractExecutionThreadService
Exception
protected void triggerShutdown()
triggerShutdown
in class AbstractExecutionThreadService
public void addWallet(Wallet wallet)
Link the given wallet to this PeerGroup. This is used for three purposes:
setFastCatchupTimeSecs(long)
, to optimize chain
download.Note that this should be done before chain download commences because if you add a wallet with keys earlier than the current chain head, the relevant parts of the chain won't be redownloaded for you.
The Wallet will have an event listener registered on it, so to avoid leaks remember to use
removeWallet(Wallet)
on it if you wish to keep the Wallet but lose the PeerGroup.
public void addPeerFilterProvider(PeerFilterProvider provider)
Link the given PeerFilterProvider to this PeerGroup. DO NOT use this for Wallets, use
addWallet(Wallet)
instead.
Note that this should be done before chain download commences because if you add a listener with keys earlier than the current chain head, the relevant parts of the chain won't be redownloaded for you.
public void removeWallet(Wallet wallet)
public void recalculateFastCatchupAndFilter(PeerGroup.FilterRecalculateMode mode)
mode
- In what situations to send the filter to connected peers.public void setBloomFilterFalsePositiveRate(double bloomFilterFPRate)
Sets the false positive rate of bloom filters given to peers. The default is DEFAULT_BLOOM_FILTER_FP_RATE
.
Be careful regenerating the bloom filter too often, as it decreases anonymity because remote nodes can compare transactions against both the new and old filters to significantly decrease the false positive rate.
See the docs for BloomFilter.BloomFilter(int, double, long, BloomFilter.BloomUpdate)
for a brief
explanation of anonymity when using bloom filters.
public int numConnectedPeers()
PeerEventListener
and use the onPeerConnected/onPeerDisconnected methods.@Nullable public Peer connectTo(InetSocketAddress address)
AbstractExecutionThreadService.start()
address
- destination IP and port.Peer.getConnectionOpenFuture()
if you
want a future which completes when the connection is open.@Nullable public Peer connectToLocalHost()
@Nullable protected Peer connectTo(PeerAddress address, boolean incrementMaxConnections, int connectTimeoutMillis)
address
- Remote network addressincrementMaxConnections
- Whether to consider this connection an attempt to fill our quota, or something
explicitly requested.public void setConnectTimeoutMillis(int connectTimeoutMillis)
public void startBlockChainDownload(PeerEventListener listener)
Start downloading the blockchain from the first available peer.
If no peers are currently connected, the download will be started once a peer starts. If the peer dies, the download will resume with another peer.
listener
- a listener for chain download events, may not be nullpublic void downloadBlockChain()
DownloadListener
for you.This method waits until the download is complete. "Complete" is defined as downloading from at least one peer all the blocks that are in that peer's inventory.
protected void handleNewPeer(Peer peer)
public MemoryPool getMemoryPool()
MemoryPool
created by this peer group to synchronize its peers. The pool tracks advertised
and downloaded transactions so their confidence can be measured as a proportion of how many peers announced it.
With an un-tampered with internet connection, the more peers announce a transaction the more confidence you can
have that it's really valid.public void setFastCatchupTimeSecs(long secondsSinceEpoch)
public long getFastCatchupTimeSecs()
addWallet(Wallet)
this just returns
the min of the wallets earliest key times.protected void handlePeerDeath(Peer peer)
public ListenableFuture<List<Peer>> waitForPeers(int numPeers)
getMaxConnections()
you can wait until the
network is fully online. To block immediately, just call get() on the result. Just calls
waitForPeersOfVersion(int, long)
with zero as the protocol version.numPeers
- How many peers to wait for.public ListenableFuture<List<Peer>> waitForPeersOfVersion(int numPeers, long protocolVersion)
numPeers
- How many peers to wait for.protocolVersion
- The protocol version the awaited peers must implement (or better).public List<Peer> findPeersOfAtLeastVersion(long protocolVersion)
public int getMinBroadcastConnections()
broadcastTransaction(Transaction)
will wait until the minimum number is reached so
propagation across the network can be observed. If no value has been set using
setMinBroadcastConnections(int)
a default of half of whatever
getMaxConnections()
returns is used.public void setMinBroadcastConnections(int value)
public ListenableFuture<Transaction> broadcastTransaction(Transaction tx)
broadcastTransaction(Transaction,int)
with getMinBroadcastConnections() as the number
of connections to wait for before commencing broadcast.broadcastTransaction
in interface TransactionBroadcaster
public ListenableFuture<Transaction> broadcastTransaction(Transaction tx, int minConnections)
Given a transaction, sends it un-announced to one peer and then waits for it to be received back from other
peers. Once all connected peers have announced the transaction, the future will be completed. If anything goes
wrong the exception will be thrown when get() is called, or you can receive it via a callback on the
ListenableFuture
. This method returns immediately, so if you want it to block just call get() on the
result.
Note that if the PeerGroup is limited to only one connection (discovery is not activated) then the future will complete as soon as the transaction was successfully written to that peer.
Other than for sending your own transactions, this method is useful if you have received a transaction from someone and want to know that it's valid. It's a bit of a weird hack because the current version of the Bitcoin protocol does not inform you if you send an invalid transaction. Because sending bad transactions counts towards your DoS limit, be careful with relaying lots of unknown transactions. Otherwise you might get kicked off the network.
The transaction won't be sent until there are at least minConnections active connections available. A good choice for proportion would be between 0.5 and 0.8 but if you want faster transmission during initial bringup of the peer group you can lower it.
public long getPingIntervalMsec()
Peer.getLastPingTime()
but it increases load on the
remote node. It defaults to 5000.public void setPingIntervalMsec(long pingIntervalMsec)
Peer.getLastPingTime()
but it increases load on the
remote node. It defaults to DEFAULT_PING_INTERVAL_MSEC
.
Setting the value to be <= 0 disables pinging entirely, although you can still request one yourself
using Peer.ping()
.public void setMinRequiredProtocolVersion(int minRequiredProtocolVersion)
public int getMinRequiredProtocolVersion()
public int getMostCommonChainHeight()
public static int getMostCommonChainHeight(List<Peer> peers)
Peer
s.
If multiple heights are tied, the highest is returned. If no peers are connected, returns zero.@Nullable protected Peer selectDownloadPeer(List<Peer> peers)
public Peer getDownloadPeer()
@Nullable public com.subgraph.orchid.TorClient getTorClient()
TorClient
object for this peer group, if Tor is in use, null otherwise.public boolean getUseLocalhostPeerWhenPossible()
public void setUseLocalhostPeerWhenPossible(boolean useLocalhostPeerWhenPossible)
Copyright © 2014. All rights reserved.