imToken v2.9.3版本的 MD5 值为:42af1a08a3f01f69d2f3782d81007b3c
以下内容为反编译后的 PeerGroup.java 源代码,内容仅作参考
package org.bitcoinj.core;
import cn.jiguang.internal.JConstants;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.net.InetAddresses;
import com.google.common.primitives.Ints;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableScheduledFuture;
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Runnables;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import com.squareup.okhttp.OkHttpClient;
import com.subgraph.orchid.TorClient;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NoRouteToHostException;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import net.jcip.annotations.GuardedBy;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.listeners.AbstractPeerEventListener;
import org.bitcoinj.core.listeners.BlocksDownloadedEventListener;
import org.bitcoinj.core.listeners.ChainDownloadStartedEventListener;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
import org.bitcoinj.core.listeners.GetDataEventListener;
import org.bitcoinj.core.listeners.OnTransactionBroadcastListener;
import org.bitcoinj.core.listeners.PeerConnectedEventListener;
import org.bitcoinj.core.listeners.PeerDataEventListener;
import org.bitcoinj.core.listeners.PeerDisconnectedEventListener;
import org.bitcoinj.core.listeners.PeerDiscoveredEventListener;
import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
import org.bitcoinj.crypto.DRMWorkaround;
import org.bitcoinj.net.BlockingClientManager;
import org.bitcoinj.net.ClientConnectionManager;
import org.bitcoinj.net.FilterMerger;
import org.bitcoinj.net.NioClientManager;
import org.bitcoinj.net.discovery.HttpDiscovery;
import org.bitcoinj.net.discovery.MultiplexingDiscovery;
import org.bitcoinj.net.discovery.PeerDiscovery;
import org.bitcoinj.net.discovery.PeerDiscoveryException;
import org.bitcoinj.net.discovery.TorDiscovery;
import org.bitcoinj.script.Script;
import org.bitcoinj.utils.ContextPropagatingThreadFactory;
import org.bitcoinj.utils.ExponentialBackoff;
import org.bitcoinj.utils.ListenerRegistration;
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.Logger;
import org.slf4j.LoggerFactory;
public class PeerGroup implements TransactionBroadcaster {
public static final double DEFAULT_BLOOM_FILTER_FP_RATE = 1.0E-5d;
public static final int DEFAULT_CONNECTIONS = 12;
public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 5000;
private static final long DEFAULT_PEER_DISCOVERY_TIMEOUT_MILLIS = 5000;
public static final long DEFAULT_PING_INTERVAL_MSEC = 2000;
public static final double MAX_FP_RATE_INCREASE = 10.0d;
private static final int TOR_TIMEOUT_SECONDS = 60;
private static final Logger log = LoggerFactory.getLogger((Class<?>) PeerGroup.class);
@GuardedBy("lock")
private final Map<PeerAddress, ExponentialBackoff> backoffMap;
private final FilterMerger bloomFilterMerger;
@Nullable
protected final AbstractBlockChain chain;
@Nullable
private ChainDownloadSpeedCalculator chainDownloadSpeedCalculator;
private final ClientConnectionManager channels;
@GuardedBy("lock")
@Nullable
private PeerDataEventListener downloadListener;
@GuardedBy("lock")
private Peer downloadPeer;
@GuardedBy("lock")
private int downloadTxDependencyDepth;
protected final ListeningScheduledExecutorService executor;
private CountDownLatch executorStartupLatch;
@GuardedBy("lock")
private long fastCatchupTimeSecs;
@GuardedBy("lock")
private ExponentialBackoff groupBackoff;
private final Map<FilterRecalculateMode, SettableFuture<BloomFilter>> inFlightRecalculations;
@GuardedBy("lock")
private final PriorityQueue<PeerAddress> inactives;
@GuardedBy("lock")
private boolean ipv6Unreachable;
private LocalhostCheckState localhostCheckState;
protected final ReentrantLock lock;
@GuardedBy("lock")
private int maxConnections;
private int minBroadcastConnections;
protected final NetworkParameters params;
private final ExponentialBackoff.Params peerBackoffParams;
protected final CopyOnWriteArrayList<ListenerRegistration<PeerConnectedEventListener>> peerConnectedEventListeners;
protected final CopyOnWriteArrayList<ListenerRegistration<PeerDisconnectedEventListener>> peerDisconnectedEventListeners;
protected final CopyOnWriteArrayList<ListenerRegistration<PeerDiscoveredEventListener>> peerDiscoveredEventListeners;
private final CopyOnWriteArraySet<PeerDiscovery> peerDiscoverers;
private final CopyOnWriteArrayList<PeerFilterProvider> peerFilterProviders;
private final CopyOnWriteArrayList<ListenerRegistration<GetDataEventListener>> peerGetDataEventListeners;
private final PeerListener peerListener;
private final CopyOnWriteArrayList<Peer> peers;
private final CopyOnWriteArrayList<ListenerRegistration<BlocksDownloadedEventListener>> peersBlocksDownloadedEventListeners;
private final CopyOnWriteArrayList<ListenerRegistration<ChainDownloadStartedEventListener>> peersChainDownloadStartedEventListeners;
private final CopyOnWriteArrayList<ListenerRegistration<PreMessageReceivedEventListener>> peersPreMessageReceivedEventListeners;
protected final CopyOnWriteArrayList<ListenerRegistration<OnTransactionBroadcastListener>> peersTransactionBroadastEventListeners;
private final CopyOnWriteArrayList<Peer> pendingPeers;
@GuardedBy("lock")
private long pingIntervalMsec;
private long requiredServices;
private final Set<TransactionBroadcast> runningBroadcasts;
@GuardedBy("lock")
private int stallMinSpeedBytesSec;
@GuardedBy("lock")
private int stallPeriodSeconds;
private final PeerStartupListener startupListener;
@Nullable
private final TorClient torClient;
private Runnable triggerConnectionsJob;
@GuardedBy("lock")
private boolean useLocalhostPeerWhenPossible;
private volatile boolean vBloomFilteringEnabled;
private volatile int vConnectTimeoutMillis;
private volatile int vMaxPeersToDiscoverCount;
private volatile int vMinRequiredProtocolVersion;
private volatile long vPeerDiscoveryTimeoutMillis;
@Nullable
private volatile ListenableScheduledFuture<?> vPingTask;
private volatile boolean vRunning;
private volatile boolean vUsedUp;
@GuardedBy("lock")
private VersionMessage versionMessage;
private final WalletCoinsReceivedEventListener walletCoinsReceivedEventListener;
private final KeyChainEventListener walletKeyEventListener;
private final ScriptsChangeEventListener walletScriptEventListener;
private final CopyOnWriteArrayList<Wallet> wallets;
public enum FilterRecalculateMode {
SEND_IF_CHANGED,
FORCE_SEND_FOR_REFRESH,
DONT_SEND
}
public enum LocalhostCheckState {
NOT_TRIED,
FOUND,
FOUND_AND_CONNECTED,
NOT_THERE
}
public class PeerListener implements GetDataEventListener, BlocksDownloadedEventListener {
public PeerListener() {
}
@Override
public List<Message> getData(Peer peer, GetDataMessage getDataMessage) {
return PeerGroup.this.handleGetData(getDataMessage);
}
@Override
public void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int i) {
if (PeerGroup.this.chain == null) {
return;
}
double falsePositiveRate = PeerGroup.this.chain.getFalsePositiveRate();
double bloomFilterFPRate = PeerGroup.this.bloomFilterMerger.getBloomFilterFPRate() * 10.0d;
if (falsePositiveRate > bloomFilterFPRate) {
if (PeerGroup.log.isDebugEnabled()) {
PeerGroup.log.debug("Force update Bloom filter due to high false positive rate ({} vs {})", Double.valueOf(falsePositiveRate), Double.valueOf(bloomFilterFPRate));
}
PeerGroup.this.recalculateFastCatchupAndFilter(FilterRecalculateMode.FORCE_SEND_FOR_REFRESH);
}
}
}
public class PeerStartupListener implements PeerConnectedEventListener, PeerDisconnectedEventListener {
private PeerStartupListener() {
}
@Override
public void onPeerConnected(Peer peer, int i) {
PeerGroup.this.handleNewPeer(peer);
}
@Override
public void onPeerDisconnected(Peer peer, int i) {
PeerGroup.this.handlePeerDeath(peer, null);
}
}
public PeerGroup(NetworkParameters networkParameters) {
this(networkParameters, (AbstractBlockChain) null);
}
public PeerGroup(Context context) {
this(context, (AbstractBlockChain) null);
}
public PeerGroup(NetworkParameters networkParameters, @Nullable AbstractBlockChain abstractBlockChain) {
this(Context.getOrCreate(networkParameters), abstractBlockChain, new NioClientManager());
}
public PeerGroup(Context context, @Nullable AbstractBlockChain abstractBlockChain) {
this(context, abstractBlockChain, new NioClientManager());
}
public static PeerGroup newWithTor(NetworkParameters networkParameters, @Nullable AbstractBlockChain abstractBlockChain, TorClient torClient) throws TimeoutException {
return newWithTor(Context.getOrCreate(networkParameters), abstractBlockChain, torClient);
}
public static PeerGroup newWithTor(Context context, @Nullable AbstractBlockChain abstractBlockChain, TorClient torClient) throws TimeoutException {
return newWithTor(context, abstractBlockChain, torClient, true);
}
public static PeerGroup newWithTor(Context context, @Nullable AbstractBlockChain abstractBlockChain, TorClient torClient, boolean z) throws TimeoutException {
Preconditions.checkNotNull(torClient);
DRMWorkaround.maybeDisableExportControls();
BlockingClientManager blockingClientManager = new BlockingClientManager(torClient.getSocketFactory());
blockingClientManager.setConnectTimeoutMillis(60000);
PeerGroup peerGroup = new PeerGroup(context, abstractBlockChain, blockingClientManager, torClient);
peerGroup.setConnectTimeoutMillis(60000);
if (z) {
NetworkParameters params = context.getParams();
HttpDiscovery.Details[] httpSeeds = params.getHttpSeeds();
if (httpSeeds.length > 0) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setSocketFactory(torClient.getSocketFactory());
ArrayList newArrayList = Lists.newArrayList();
for (HttpDiscovery.Details details : httpSeeds) {
newArrayList.add(new HttpDiscovery(params, details, okHttpClient));
}
peerGroup.addPeerDiscovery(new MultiplexingDiscovery(params, newArrayList));
} else {
peerGroup.addPeerDiscovery(new TorDiscovery(params, torClient));
}
}
return peerGroup;
}
public PeerGroup(NetworkParameters networkParameters, @Nullable AbstractBlockChain abstractBlockChain, ClientConnectionManager clientConnectionManager) {
this(Context.getOrCreate(networkParameters), abstractBlockChain, clientConnectionManager, null);
}
public PeerGroup(Context context, @Nullable AbstractBlockChain abstractBlockChain, ClientConnectionManager clientConnectionManager) {
this(context, abstractBlockChain, clientConnectionManager, null);
}
private PeerGroup(Context context, @Nullable AbstractBlockChain abstractBlockChain, ClientConnectionManager clientConnectionManager, @Nullable TorClient torClient) {
this.requiredServices = 0L;
this.vMaxPeersToDiscoverCount = 100;
this.vPeerDiscoveryTimeoutMillis = 5000L;
this.lock = Threading.lock("peergroup");
this.peersBlocksDownloadedEventListeners = new CopyOnWriteArrayList<>();
this.peersChainDownloadStartedEventListeners = new CopyOnWriteArrayList<>();
this.peerConnectedEventListeners = new CopyOnWriteArrayList<>();
this.peerDiscoveredEventListeners = new CopyOnWriteArrayList<>();
this.peerDisconnectedEventListeners = new CopyOnWriteArrayList<>();
this.peerGetDataEventListeners = new CopyOnWriteArrayList<>();
this.peersPreMessageReceivedEventListeners = new CopyOnWriteArrayList<>();
this.peersTransactionBroadastEventListeners = new CopyOnWriteArrayList<>();
this.pingIntervalMsec = 2000L;
this.useLocalhostPeerWhenPossible = true;
this.ipv6Unreachable = false;
this.peerListener = new PeerListener();
this.minBroadcastConnections = 0;
this.walletScriptEventListener = new ScriptsChangeEventListener() {
@Override
public void onScriptsChanged(Wallet wallet, List<Script> list, boolean z) {
PeerGroup.this.recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
}
};
this.walletKeyEventListener = new KeyChainEventListener() {
@Override
public void onKeysAdded(List<ECKey> list) {
PeerGroup.this.recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
}
};
this.walletCoinsReceivedEventListener = new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction transaction, Coin coin, Coin coin2) {
for (TransactionOutput transactionOutput : transaction.getOutputs()) {
if (transactionOutput.getScriptPubKey().isSentToRawPubKey() && transactionOutput.isMine(wallet)) {
if (transaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
PeerGroup.this.recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
return;
} else {
PeerGroup.this.recalculateFastCatchupAndFilter(FilterRecalculateMode.DONT_SEND);
return;
}
}
}
}
};
this.peerBackoffParams = new ExponentialBackoff.Params(1000L, 1.5f, 600000L);
this.groupBackoff = new ExponentialBackoff(new ExponentialBackoff.Params(1000L, 1.5f, 10000L));
this.startupListener = new PeerStartupListener();
this.vConnectTimeoutMillis = 5000;
this.vBloomFilteringEnabled = true;
this.executorStartupLatch = new CountDownLatch(1);
this.triggerConnectionsJob = new Runnable() {
private static final long MIN_PEER_DISCOVERY_INTERVAL = 1000;
private boolean firstRun = true;
@Override
public void run() {
try {
go();
} catch (Throwable th) {
PeerGroup.log.error("Exception when trying to build connections", th);
}
}
public void go() {
PeerGroup peerGroup;
ReentrantLock reentrantLock;
PeerAddress peerAddress;
String str;
if (PeerGroup.this.vRunning) {
long currentTimeMillis = Utils.currentTimeMillis();
PeerGroup.this.lock.lock();
try {
if (!Utils.isAndroidRuntime() && PeerGroup.this.useLocalhostPeerWhenPossible && PeerGroup.this.maybeCheckForLocalhostPeer() && this.firstRun) {
PeerGroup.log.info("Localhost peer detected, trying to use it instead of P2P discovery");
PeerGroup.this.maxConnections = 0;
PeerGroup.this.connectToLocalHost();
return;
}
boolean z = true;
boolean z2 = !(!PeerGroup.this.inactives.isEmpty() && ((ExponentialBackoff) PeerGroup.this.backoffMap.get(PeerGroup.this.inactives.peek())).getRetryTime() <= currentTimeMillis);
if (z2) {
try {
} catch (PeerDiscoveryException e) {
PeerGroup.log.error("Peer discovery failure", (Throwable) e);
}
}
z = false;
PeerGroup.this.lock.lock();
if (z2) {
if (z) {
try {
if (PeerGroup.this.countConnectedAndPendingPeers() >= PeerGroup.this.getMaxConnections()) {
PeerGroup.this.groupBackoff.trackSuccess();
}
} finally {
PeerGroup.this.lock.unlock();
}
}
PeerGroup.this.groupBackoff.trackFailure();
}
if (PeerGroup.this.inactives.isEmpty()) {
if (PeerGroup.this.countConnectedAndPendingPeers() < PeerGroup.this.getMaxConnections()) {
long max = Math.max(PeerGroup.this.groupBackoff.getRetryTime() - currentTimeMillis, 1000L);
PeerGroup.log.info("Peer discovery didn't provide us any more peers, will try again in " + max + "ms.");
PeerGroup.this.executor.schedule((Runnable) this, max, TimeUnit.MILLISECONDS);
}
return;
}
do {
peerAddress = (PeerAddress) PeerGroup.this.inactives.poll();
if (!PeerGroup.this.ipv6Unreachable) {
break;
}
} while (peerAddress.getAddr() instanceof Inet6Address);
long max2 = Math.max(((ExponentialBackoff) PeerGroup.this.backoffMap.get(peerAddress)).getRetryTime(), PeerGroup.this.groupBackoff.getRetryTime());
if (max2 <= currentTimeMillis) {
PeerGroup.this.connectTo(peerAddress, false, PeerGroup.this.vConnectTimeoutMillis);
PeerGroup.this.lock.unlock();
if (PeerGroup.this.countConnectedAndPendingPeers() < PeerGroup.this.getMaxConnections()) {
PeerGroup.this.executor.execute(this);
return;
}
return;
}
long j = max2 - currentTimeMillis;
Logger logger = PeerGroup.log;
Long valueOf = Long.valueOf(j);
if (peerAddress == null) {
str = "";
} else {
str = "to " + peerAddress;
}
logger.info("Waiting {} msec before next connect attempt {}", valueOf, str);
PeerGroup.this.inactives.add(peerAddress);
PeerGroup.this.executor.schedule((Runnable) this, j, TimeUnit.MILLISECONDS);
} finally {
this.firstRun = false;
}
}
}
};
this.localhostCheckState = LocalhostCheckState.NOT_TRIED;
this.inFlightRecalculations = Maps.newHashMap();
this.stallPeriodSeconds = 10;
this.stallMinSpeedBytesSec = 1600;
Preconditions.checkNotNull(context);
NetworkParameters params = context.getParams();
this.params = params;
this.chain = abstractBlockChain;
this.fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds();
this.wallets = new CopyOnWriteArrayList<>();
this.peerFilterProviders = new CopyOnWriteArrayList<>();
this.torClient = torClient;
this.executor = createPrivateExecutor();
this.maxConnections = 0;
VersionMessage versionMessage = new VersionMessage(this.params, abstractBlockChain != null ? abstractBlockChain.getBestChainHeight() : 0);
this.versionMessage = versionMessage;
versionMessage.relayTxesBeforeFilter = true;
this.downloadTxDependencyDepth = Integer.MAX_VALUE;
this.inactives = new PriorityQueue<>(1, new Comparator<PeerAddress>() {
@Override
public int compare(PeerAddress peerAddress, PeerAddress peerAddress2) {
Preconditions.checkState(PeerGroup.this.lock.isHeldByCurrentThread());
int compareTo = ((ExponentialBackoff) PeerGroup.this.backoffMap.get(peerAddress)).compareTo((ExponentialBackoff) PeerGroup.this.backoffMap.get(peerAddress2));
return compareTo == 0 ? Ints.compare(peerAddress.getPort(), peerAddress2.getPort()) : compareTo;
}
});
this.backoffMap = new HashMap();
this.peers = new CopyOnWriteArrayList<>();
this.pendingPeers = new CopyOnWriteArrayList<>();
this.channels = clientConnectionManager;
this.peerDiscoverers = new CopyOnWriteArraySet<>();
this.runningBroadcasts = Collections.synchronizedSet(new HashSet());
this.bloomFilterMerger = new FilterMerger(1.0E-5d);
this.vMinRequiredProtocolVersion = this.params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.BLOOM_FILTER);
}
protected ListeningScheduledExecutorService createPrivateExecutor() {
ListeningScheduledExecutorService listeningDecorator = MoreExecutors.listeningDecorator((ScheduledExecutorService) new ScheduledThreadPoolExecutor(1, new ContextPropagatingThreadFactory("PeerGroup Thread")));
listeningDecorator.execute(new Runnable() {
@Override
public void run() {
Uninterruptibles.awaitUninterruptibly(PeerGroup.this.executorStartupLatch);
}
});
return listeningDecorator;
}
public void setPeerDiscoveryTimeoutMillis(long j) {
this.vPeerDiscoveryTimeoutMillis = j;
}
public void setMaxConnections(int i) {
this.lock.lock();
try {
this.maxConnections = i;
if (isRunning()) {
this.lock.unlock();
int connectedClientCount = i - this.channels.getConnectedClientCount();
if (connectedClientCount > 0) {
triggerConnections();
}
if (connectedClientCount < 0) {
this.channels.closeConnections(-connectedClientCount);
}
}
} finally {
this.lock.unlock();
}
}
public void setDownloadTxDependencies(int i) {
this.lock.lock();
try {
this.downloadTxDependencyDepth = i;
} finally {
this.lock.unlock();
}
}
public void triggerConnections() {
if (this.executor.isShutdown()) {
return;
}
this.executor.execute(this.triggerConnectionsJob);
}
public int getMaxConnections() {
this.lock.lock();
try {
return this.maxConnections;
} finally {
this.lock.unlock();
}
}
public List<Message> handleGetData(GetDataMessage getDataMessage) {
this.lock.lock();
try {
LinkedList linkedList = new LinkedList();
Iterator it = new LinkedList(getDataMessage.getItems()).iterator();
while (it.hasNext()) {
InventoryItem inventoryItem = (InventoryItem) it.next();
Iterator<Wallet> it2 = this.wallets.iterator();
while (true) {
if (!it2.hasNext()) {
break;
}
Transaction transaction = it2.next().getTransaction(inventoryItem.hash);
if (transaction != null) {
linkedList.add(transaction);
it.remove();
break;
}
}
}
return linkedList;
} finally {
this.lock.unlock();
}
}
public void setVersionMessage(VersionMessage versionMessage) {
this.lock.lock();
try {
this.versionMessage = versionMessage;
} finally {
this.lock.unlock();
}
}
public VersionMessage getVersionMessage() {
this.lock.lock();
try {
return this.versionMessage;
} finally {
this.lock.unlock();
}
}
public void setUserAgent(String str, String str2, @Nullable String str3) {
AbstractBlockChain abstractBlockChain = this.chain;
VersionMessage versionMessage = new VersionMessage(this.params, abstractBlockChain == null ? 0 : abstractBlockChain.getBestChainHeight());
versionMessage.relayTxesBeforeFilter = false;
updateVersionMessageRelayTxesBeforeFilter(versionMessage);
versionMessage.appendToSubVer(str, str2, str3);
setVersionMessage(versionMessage);
}
private void updateVersionMessageRelayTxesBeforeFilter(VersionMessage versionMessage) {
this.lock.lock();
try {
boolean z = true;
if ((this.chain != null && !this.chain.shouldVerifyTransactions()) && this.peerFilterProviders.size() > 0 && this.vBloomFilteringEnabled) {
z = false;
}
versionMessage.relayTxesBeforeFilter = z;
} finally {
this.lock.unlock();
}
}
public void setUserAgent(String str, String str2) {
setUserAgent(str, str2, null);
}
@Deprecated
public void addEventListener(AbstractPeerEventListener abstractPeerEventListener, Executor executor) {
addBlocksDownloadedEventListener(Threading.USER_THREAD, abstractPeerEventListener);
addChainDownloadStartedEventListener(Threading.USER_THREAD, abstractPeerEventListener);
addConnectedEventListener(Threading.USER_THREAD, abstractPeerEventListener);
addDisconnectedEventListener(Threading.USER_THREAD, abstractPeerEventListener);
addDiscoveredEventListener(Threading.USER_THREAD, abstractPeerEventListener);
addGetDataEventListener(Threading.USER_THREAD, abstractPeerEventListener);
addOnTransactionBroadcastListener(Threading.USER_THREAD, abstractPeerEventListener);
addPreMessageReceivedEventListener(Threading.USER_THREAD, abstractPeerEventListener);
}
@Deprecated
public void addEventListener(AbstractPeerEventListener abstractPeerEventListener) {
addBlocksDownloadedEventListener(this.executor, abstractPeerEventListener);
addChainDownloadStartedEventListener(this.executor, abstractPeerEventListener);
addConnectedEventListener(this.executor, abstractPeerEventListener);
addDisconnectedEventListener(this.executor, abstractPeerEventListener);
addDiscoveredEventListener(this.executor, abstractPeerEventListener);
addGetDataEventListener(this.executor, abstractPeerEventListener);
addOnTransactionBroadcastListener(this.executor, abstractPeerEventListener);
addPreMessageReceivedEventListener(this.executor, abstractPeerEventListener);
}
public void addBlocksDownloadedEventListener(BlocksDownloadedEventListener blocksDownloadedEventListener) {
addBlocksDownloadedEventListener(Threading.USER_THREAD, blocksDownloadedEventListener);
}
public void addBlocksDownloadedEventListener(Executor executor, BlocksDownloadedEventListener blocksDownloadedEventListener) {
this.peersBlocksDownloadedEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(blocksDownloadedEventListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addBlocksDownloadedEventListener(executor, blocksDownloadedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addBlocksDownloadedEventListener(executor, blocksDownloadedEventListener);
}
}
public void addChainDownloadStartedEventListener(ChainDownloadStartedEventListener chainDownloadStartedEventListener) {
addChainDownloadStartedEventListener(Threading.USER_THREAD, chainDownloadStartedEventListener);
}
public void addChainDownloadStartedEventListener(Executor executor, ChainDownloadStartedEventListener chainDownloadStartedEventListener) {
this.peersChainDownloadStartedEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(chainDownloadStartedEventListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addChainDownloadStartedEventListener(executor, chainDownloadStartedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addChainDownloadStartedEventListener(executor, chainDownloadStartedEventListener);
}
}
public void addConnectedEventListener(PeerConnectedEventListener peerConnectedEventListener) {
addConnectedEventListener(Threading.USER_THREAD, peerConnectedEventListener);
}
public void addConnectedEventListener(Executor executor, PeerConnectedEventListener peerConnectedEventListener) {
this.peerConnectedEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(peerConnectedEventListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addConnectedEventListener(executor, peerConnectedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addConnectedEventListener(executor, peerConnectedEventListener);
}
}
public void addDisconnectedEventListener(PeerDisconnectedEventListener peerDisconnectedEventListener) {
addDisconnectedEventListener(Threading.USER_THREAD, peerDisconnectedEventListener);
}
public void addDisconnectedEventListener(Executor executor, PeerDisconnectedEventListener peerDisconnectedEventListener) {
this.peerDisconnectedEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(peerDisconnectedEventListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addDisconnectedEventListener(executor, peerDisconnectedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addDisconnectedEventListener(executor, peerDisconnectedEventListener);
}
}
public void addDiscoveredEventListener(PeerDiscoveredEventListener peerDiscoveredEventListener) {
addDiscoveredEventListener(Threading.USER_THREAD, peerDiscoveredEventListener);
}
public void addDiscoveredEventListener(Executor executor, PeerDiscoveredEventListener peerDiscoveredEventListener) {
this.peerDiscoveredEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(peerDiscoveredEventListener), executor));
}
public void addGetDataEventListener(GetDataEventListener getDataEventListener) {
addGetDataEventListener(Threading.USER_THREAD, getDataEventListener);
}
public void addGetDataEventListener(Executor executor, GetDataEventListener getDataEventListener) {
this.peerGetDataEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(getDataEventListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addGetDataEventListener(executor, getDataEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addGetDataEventListener(executor, getDataEventListener);
}
}
public void addOnTransactionBroadcastListener(OnTransactionBroadcastListener onTransactionBroadcastListener) {
addOnTransactionBroadcastListener(Threading.USER_THREAD, onTransactionBroadcastListener);
}
public void addOnTransactionBroadcastListener(Executor executor, OnTransactionBroadcastListener onTransactionBroadcastListener) {
this.peersTransactionBroadastEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(onTransactionBroadcastListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addOnTransactionBroadcastListener(executor, onTransactionBroadcastListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addOnTransactionBroadcastListener(executor, onTransactionBroadcastListener);
}
}
public void addPreMessageReceivedEventListener(PreMessageReceivedEventListener preMessageReceivedEventListener) {
addPreMessageReceivedEventListener(Threading.USER_THREAD, preMessageReceivedEventListener);
}
public void addPreMessageReceivedEventListener(Executor executor, PreMessageReceivedEventListener preMessageReceivedEventListener) {
this.peersPreMessageReceivedEventListeners.add(new ListenerRegistration<>(Preconditions.checkNotNull(preMessageReceivedEventListener), executor));
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().addPreMessageReceivedEventListener(executor, preMessageReceivedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().addPreMessageReceivedEventListener(executor, preMessageReceivedEventListener);
}
}
@Deprecated
public void removeEventListener(AbstractPeerEventListener abstractPeerEventListener) {
removeBlocksDownloadedEventListener(abstractPeerEventListener);
removeChainDownloadStartedEventListener(abstractPeerEventListener);
removeConnectedEventListener(abstractPeerEventListener);
removeDisconnectedEventListener(abstractPeerEventListener);
removeDiscoveredEventListener(abstractPeerEventListener);
removeGetDataEventListener(abstractPeerEventListener);
removeOnTransactionBroadcastListener(abstractPeerEventListener);
removePreMessageReceivedEventListener(abstractPeerEventListener);
}
public boolean removeBlocksDownloadedEventListener(BlocksDownloadedEventListener blocksDownloadedEventListener) {
boolean removeFromList = ListenerRegistration.removeFromList(blocksDownloadedEventListener, this.peersBlocksDownloadedEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removeBlocksDownloadedEventListener(blocksDownloadedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removeBlocksDownloadedEventListener(blocksDownloadedEventListener);
}
return removeFromList;
}
public boolean removeChainDownloadStartedEventListener(ChainDownloadStartedEventListener chainDownloadStartedEventListener) {
boolean removeFromList = ListenerRegistration.removeFromList(chainDownloadStartedEventListener, this.peersChainDownloadStartedEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removeChainDownloadStartedEventListener(chainDownloadStartedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removeChainDownloadStartedEventListener(chainDownloadStartedEventListener);
}
return removeFromList;
}
public boolean removeConnectedEventListener(PeerConnectedEventListener peerConnectedEventListener) {
boolean removeFromList = ListenerRegistration.removeFromList(peerConnectedEventListener, this.peerConnectedEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removeConnectedEventListener(peerConnectedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removeConnectedEventListener(peerConnectedEventListener);
}
return removeFromList;
}
public boolean removeDisconnectedEventListener(PeerDisconnectedEventListener peerDisconnectedEventListener) {
boolean removeFromList = ListenerRegistration.removeFromList(peerDisconnectedEventListener, this.peerDisconnectedEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removeDisconnectedEventListener(peerDisconnectedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removeDisconnectedEventListener(peerDisconnectedEventListener);
}
return removeFromList;
}
public boolean removeDiscoveredEventListener(PeerDiscoveredEventListener peerDiscoveredEventListener) {
return ListenerRegistration.removeFromList(peerDiscoveredEventListener, this.peerDiscoveredEventListeners);
}
public boolean removeGetDataEventListener(GetDataEventListener getDataEventListener) {
boolean removeFromList = ListenerRegistration.removeFromList(getDataEventListener, this.peerGetDataEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removeGetDataEventListener(getDataEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removeGetDataEventListener(getDataEventListener);
}
return removeFromList;
}
public boolean removeOnTransactionBroadcastListener(OnTransactionBroadcastListener onTransactionBroadcastListener) {
boolean removeFromList = ListenerRegistration.removeFromList(onTransactionBroadcastListener, this.peersTransactionBroadastEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removeOnTransactionBroadcastListener(onTransactionBroadcastListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removeOnTransactionBroadcastListener(onTransactionBroadcastListener);
}
return removeFromList;
}
public boolean removePreMessageReceivedEventListener(PreMessageReceivedEventListener preMessageReceivedEventListener) {
boolean removeFromList = ListenerRegistration.removeFromList(preMessageReceivedEventListener, this.peersPreMessageReceivedEventListeners);
Iterator<Peer> it = getConnectedPeers().iterator();
while (it.hasNext()) {
it.next().removePreMessageReceivedEventListener(preMessageReceivedEventListener);
}
Iterator<Peer> it2 = getPendingPeers().iterator();
while (it2.hasNext()) {
it2.next().removePreMessageReceivedEventListener(preMessageReceivedEventListener);
}
return removeFromList;
}
public List<Peer> getConnectedPeers() {
this.lock.lock();
try {
return new ArrayList(this.peers);
} finally {
this.lock.unlock();
}
}
public List<Peer> getPendingPeers() {
this.lock.lock();
try {
return new ArrayList(this.pendingPeers);
} finally {
this.lock.unlock();
}
}
public void addAddress(PeerAddress peerAddress) {
this.lock.lock();
try {
addInactive(peerAddress);
int maxConnections = getMaxConnections() + 1;
this.lock.unlock();
setMaxConnections(maxConnections);
} catch (Throwable th) {
this.lock.unlock();
throw th;
}
}
private void addInactive(PeerAddress peerAddress) {
this.lock.lock();
try {
if (this.backoffMap.containsKey(peerAddress)) {
return;
}
this.backoffMap.put(peerAddress, new ExponentialBackoff(this.peerBackoffParams));
this.inactives.offer(peerAddress);
} finally {
this.lock.unlock();
}
}
public void setRequiredServices(long j) {
this.lock.lock();
try {
this.requiredServices = j;
this.peerDiscoverers.clear();
addPeerDiscovery(MultiplexingDiscovery.forServices(this.params, j));
} finally {
this.lock.unlock();
}
}
public void addAddress(InetAddress inetAddress) {
NetworkParameters networkParameters = this.params;
addAddress(new PeerAddress(networkParameters, inetAddress, networkParameters.getPort()));
}
public void addPeerDiscovery(PeerDiscovery peerDiscovery) {
this.lock.lock();
try {
if (getMaxConnections() == 0) {
setMaxConnections(12);
}
this.peerDiscoverers.add(peerDiscovery);
} finally {
this.lock.unlock();
}
}
protected int discoverPeers() throws PeerDiscoveryException {
Preconditions.checkState(!this.lock.isHeldByCurrentThread());
int i = this.vMaxPeersToDiscoverCount;
long j = this.vPeerDiscoveryTimeoutMillis;
Stopwatch createStarted = Stopwatch.createStarted();
LinkedList newLinkedList = Lists.newLinkedList();
Iterator<PeerDiscovery> it = this.peerDiscoverers.iterator();
while (it.hasNext()) {
for (InetSocketAddress inetSocketAddress : it.next().getPeers(this.requiredServices, j, TimeUnit.MILLISECONDS)) {
newLinkedList.add(new PeerAddress(this.params, inetSocketAddress));
}
if (newLinkedList.size() >= i) {
break;
}
}
if (!newLinkedList.isEmpty()) {
Iterator it2 = newLinkedList.iterator();
while (it2.hasNext()) {
addInactive((PeerAddress) it2.next());
}
final ImmutableSet copyOf = ImmutableSet.copyOf((Collection) newLinkedList);
Iterator<ListenerRegistration<PeerDiscoveredEventListener>> it3 = this.peerDiscoveredEventListeners.iterator();
while (it3.hasNext()) {
final ListenerRegistration<PeerDiscoveredEventListener> next = it3.next();
next.executor.execute(new Runnable() {
@Override
public void run() {
((PeerDiscoveredEventListener) next.listener).onPeersDiscovered(copyOf);
}
});
}
}
createStarted.stop();
log.info("Peer discovery took {} and returned {} items", createStarted, Integer.valueOf(newLinkedList.size()));
return newLinkedList.size();
}
void waitForJobQueue() {
Futures.getUnchecked(this.executor.submit(Runnables.doNothing()));
}
public int countConnectedAndPendingPeers() {
this.lock.lock();
try {
return this.peers.size() + this.pendingPeers.size();
} finally {
this.lock.unlock();
}
}
public boolean maybeCheckForLocalhostPeer() {
Socket socket;
Throwable th;
Preconditions.checkState(this.lock.isHeldByCurrentThread());
if (this.localhostCheckState != LocalhostCheckState.NOT_TRIED) {
return false;
}
Socket socket2 = null;
try {
try {
socket = new Socket();
} catch (Throwable th2) {
socket = null;
th = th2;
}
} catch (IOException unused) {
}
try {
socket.connect(new InetSocketAddress(InetAddresses.forString("127.0.0.1"), this.params.getPort()), this.vConnectTimeoutMillis);
this.localhostCheckState = LocalhostCheckState.FOUND;
try {
socket.close();
} catch (IOException unused2) {
}
return true;
} catch (IOException unused3) {
socket2 = socket;
log.info("Localhost peer not detected.");
this.localhostCheckState = LocalhostCheckState.NOT_THERE;
if (socket2 == null) {
return false;
}
try {
socket2.close();
return false;
} catch (IOException unused4) {
return false;
}
} catch (Throwable th3) {
th = th3;
if (socket != null) {
try {
socket.close();
} catch (IOException unused5) {
}
}
throw th;
}
}
public ListenableFuture startAsync() {
if (this.chain == null) {
log.warn("Starting up with no attached block chain. Did you forget to pass one to the constructor?");
}
Preconditions.checkState(!this.vUsedUp, "Cannot start a peer group twice");
this.vRunning = true;
this.vUsedUp = true;
this.executorStartupLatch.countDown();
return this.executor.submit(new Runnable() {
@Override
public void run() {
try {
PeerGroup.log.info("Starting ...");
if (PeerGroup.this.torClient != null) {
PeerGroup.log.info("Starting Tor/Orchid ...");
PeerGroup.this.torClient.start();
try {
PeerGroup.this.torClient.waitUntilReady(JConstants.MIN);
PeerGroup.log.info("Tor ready");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
PeerGroup.this.channels.startAsync();
PeerGroup.this.channels.awaitRunning();
PeerGroup.this.triggerConnections();
PeerGroup.this.setupPinging();
} catch (Throwable th) {
PeerGroup.log.error("Exception when starting up", th);
}
}
});
}
public void start() {
Futures.getUnchecked(startAsync());
}
@Deprecated
public void awaitRunning() {
waitForJobQueue();
}
public ListenableFuture stopAsync() {
Preconditions.checkState(this.vRunning);
this.vRunning = false;
ListenableFuture<?> submit = this.executor.submit(new Runnable() {
@Override
public void run() {
try {
PeerGroup.log.info("Stopping ...");
PeerGroup.this.channels.stopAsync();
PeerGroup.this.channels.awaitTerminated();
Iterator it = PeerGroup.this.peerDiscoverers.iterator();
while (it.hasNext()) {
((PeerDiscovery) it.next()).shutdown();
}
if (PeerGroup.this.torClient != null) {
PeerGroup.this.torClient.stop();
}
PeerGroup.this.vRunning = false;
PeerGroup.log.info("Stopped.");
} catch (Throwable th) {
PeerGroup.log.error("Exception when shutting down", th);
}
}
});
this.executor.shutdown();
return submit;
}
public void stop() {
try {
stopAsync();
log.info("Awaiting PeerGroup shutdown ...");
this.executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Deprecated
public void awaitTerminated() {
try {
this.executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void addWallet(Wallet wallet) {
this.lock.lock();
try {
Preconditions.checkNotNull(wallet);
Preconditions.checkState(!this.wallets.contains(wallet));
this.wallets.add(wallet);
wallet.setTransactionBroadcaster(this);
wallet.addCoinsReceivedEventListener(Threading.SAME_THREAD, this.walletCoinsReceivedEventListener);
wallet.addKeyChainEventListener(Threading.SAME_THREAD, this.walletKeyEventListener);
wallet.addScriptChangeEventListener(Threading.SAME_THREAD, this.walletScriptEventListener);
addPeerFilterProvider(wallet);
Iterator<Peer> it = this.peers.iterator();
while (it.hasNext()) {
it.next().addWallet(wallet);
}
} finally {
this.lock.unlock();
}
}
public ListenableFuture<BloomFilter> addPeerFilterProvider(PeerFilterProvider peerFilterProvider) {
this.lock.lock();
try {
Preconditions.checkNotNull(peerFilterProvider);
Preconditions.checkState(!this.peerFilterProviders.contains(peerFilterProvider));
this.peerFilterProviders.add(0, peerFilterProvider);
ListenableFuture<BloomFilter> recalculateFastCatchupAndFilter = recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
updateVersionMessageRelayTxesBeforeFilter(getVersionMessage());
return recalculateFastCatchupAndFilter;
} finally {
this.lock.unlock();
}
}
public void removePeerFilterProvider(PeerFilterProvider peerFilterProvider) {
this.lock.lock();
try {
Preconditions.checkNotNull(peerFilterProvider);
Preconditions.checkArgument(this.peerFilterProviders.remove(peerFilterProvider));
} finally {
this.lock.unlock();
}
}
public void removeWallet(Wallet wallet) {
this.wallets.remove(Preconditions.checkNotNull(wallet));
this.peerFilterProviders.remove(wallet);
wallet.removeCoinsReceivedEventListener(this.walletCoinsReceivedEventListener);
wallet.removeKeyChainEventListener(this.walletKeyEventListener);
wallet.removeScriptChangeEventListener(this.walletScriptEventListener);
wallet.setTransactionBroadcaster(null);
Iterator<Peer> it = this.peers.iterator();
while (it.hasNext()) {
it.next().removeWallet(wallet);
}
}
public ListenableFuture<BloomFilter> recalculateFastCatchupAndFilter(final FilterRecalculateMode filterRecalculateMode) {
final SettableFuture<BloomFilter> create = SettableFuture.create();
synchronized (this.inFlightRecalculations) {
if (this.inFlightRecalculations.get(filterRecalculateMode) != null) {
return this.inFlightRecalculations.get(filterRecalculateMode);
}
this.inFlightRecalculations.put(filterRecalculateMode, create);
try {
this.executor.execute(new Runnable() {
@Override
public void run() {
try {
go();
} catch (Throwable th) {
PeerGroup.log.error("Exception when trying to recalculate Bloom filter", th);
}
}
public void go() {
boolean z;
Preconditions.checkState(!PeerGroup.this.lock.isHeldByCurrentThread());
if ((PeerGroup.this.chain == null || !PeerGroup.this.chain.shouldVerifyTransactions()) && PeerGroup.this.vBloomFilteringEnabled) {
FilterMerger.Result calculate = PeerGroup.this.bloomFilterMerger.calculate(ImmutableList.copyOf((Collection) PeerGroup.this.peerFilterProviders));
int i = AnonymousClass17.$SwitchMap$org$bitcoinj$core$PeerGroup$FilterRecalculateMode[filterRecalculateMode.ordinal()];
if (i == 1) {
z = calculate.changed;
} else if (i == 2) {
z = false;
} else {
if (i != 3) {
throw new UnsupportedOperationException();
}
z = true;
}
if (z) {
Iterator it = PeerGroup.this.peers.iterator();
while (it.hasNext()) {
((Peer) it.next()).setBloomFilter(calculate.filter, filterRecalculateMode != FilterRecalculateMode.FORCE_SEND_FOR_REFRESH);
}
if (PeerGroup.this.chain != null) {
PeerGroup.this.chain.resetFalsePositiveEstimate();
}
}
PeerGroup.this.setFastCatchupTimeSecs(calculate.earliestKeyTimeSecs);
synchronized (PeerGroup.this.inFlightRecalculations) {
PeerGroup.this.inFlightRecalculations.put(filterRecalculateMode, null);
}
create.set(calculate.filter);
}
}
});
} catch (RejectedExecutionException unused) {
}
return create;
}
}
public static class AnonymousClass17 {
static final int[] $SwitchMap$org$bitcoinj$core$PeerGroup$FilterRecalculateMode;
static {
int[] iArr = new int[FilterRecalculateMode.values().length];
$SwitchMap$org$bitcoinj$core$PeerGroup$FilterRecalculateMode = iArr;
try {
iArr[FilterRecalculateMode.SEND_IF_CHANGED.ordinal()] = 1;
} catch (NoSuchFieldError unused) {
}
try {
$SwitchMap$org$bitcoinj$core$PeerGroup$FilterRecalculateMode[FilterRecalculateMode.DONT_SEND.ordinal()] = 2;
} catch (NoSuchFieldError unused2) {
}
try {
$SwitchMap$org$bitcoinj$core$PeerGroup$FilterRecalculateMode[FilterRecalculateMode.FORCE_SEND_FOR_REFRESH.ordinal()] = 3;
} catch (NoSuchFieldError unused3) {
}
}
}
public void setBloomFilterFalsePositiveRate(double d) {
this.lock.lock();
try {
this.bloomFilterMerger.setBloomFilterFPRate(d);
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
} finally {
this.lock.unlock();
}
}
public int numConnectedPeers() {
return this.peers.size();
}
@Nullable
public Peer connectTo(InetSocketAddress inetSocketAddress) {
this.lock.lock();
try {
PeerAddress peerAddress = new PeerAddress(this.params, inetSocketAddress);
this.backoffMap.put(peerAddress, new ExponentialBackoff(this.peerBackoffParams));
return connectTo(peerAddress, true, this.vConnectTimeoutMillis);
} finally {
this.lock.unlock();
}
}
@Nullable
public Peer connectToLocalHost() {
this.lock.lock();
try {
PeerAddress localhost = PeerAddress.localhost(this.params);
this.backoffMap.put(localhost, new ExponentialBackoff(this.peerBackoffParams));
return connectTo(localhost, true, this.vConnectTimeoutMillis);
} finally {
this.lock.unlock();
}
}
@GuardedBy("lock")
@Nullable
protected Peer connectTo(PeerAddress peerAddress, boolean z, int i) {
Preconditions.checkState(this.lock.isHeldByCurrentThread());
VersionMessage duplicate = getVersionMessage().duplicate();
duplicate.bestHeight = this.chain == null ? 0L : r1.getBestChainHeight();
duplicate.time = Utils.currentTimeSeconds();
Peer createPeer = createPeer(peerAddress, duplicate);
createPeer.addConnectedEventListener(Threading.SAME_THREAD, this.startupListener);
createPeer.addDisconnectedEventListener(Threading.SAME_THREAD, this.startupListener);
createPeer.setMinProtocolVersion(this.vMinRequiredProtocolVersion);
this.pendingPeers.add(createPeer);
try {
log.info("Attempting connection to {} ({} connected, {} pending, {} max)", peerAddress, Integer.valueOf(this.peers.size()), Integer.valueOf(this.pendingPeers.size()), Integer.valueOf(this.maxConnections));
ListenableFuture<SocketAddress> openConnection = this.channels.openConnection(peerAddress.toSocketAddress(), createPeer);
if (openConnection.isDone()) {
Uninterruptibles.getUninterruptibly(openConnection);
}
createPeer.setSocketTimeout(i);
if (z) {
this.maxConnections++;
}
return createPeer;
} catch (ExecutionException e) {
Throwable rootCause = Throwables.getRootCause(e);
log.warn("Failed to connect to " + peerAddress + ": " + rootCause.getMessage());
handlePeerDeath(createPeer, rootCause);
return null;
}
}
@GuardedBy("lock")
protected Peer createPeer(PeerAddress peerAddress, VersionMessage versionMessage) {
return new Peer(this.params, versionMessage, peerAddress, this.chain, this.downloadTxDependencyDepth);
}
public void setConnectTimeoutMillis(int i) {
this.vConnectTimeoutMillis = i;
}
public void startBlockChainDownload(PeerDataEventListener peerDataEventListener) {
this.lock.lock();
try {
if (this.downloadPeer != null) {
if (this.downloadListener != null) {
removeDataEventListenerFromPeer(this.downloadPeer, this.downloadListener);
}
if (peerDataEventListener != null) {
addDataEventListenerToPeer(Threading.USER_THREAD, this.downloadPeer, peerDataEventListener);
}
}
this.downloadListener = peerDataEventListener;
if (!this.peers.isEmpty()) {
startBlockChainDownloadFromPeer(this.peers.iterator().next());
}
} finally {
this.lock.unlock();
}
}
private static void addDataEventListenerToPeer(Executor executor, Peer peer, PeerDataEventListener peerDataEventListener) {
peer.addBlocksDownloadedEventListener(executor, peerDataEventListener);
peer.addChainDownloadStartedEventListener(executor, peerDataEventListener);
peer.addGetDataEventListener(executor, peerDataEventListener);
peer.addPreMessageReceivedEventListener(executor, peerDataEventListener);
}
private static void removeDataEventListenerFromPeer(Peer peer, PeerDataEventListener peerDataEventListener) {
peer.removeBlocksDownloadedEventListener(peerDataEventListener);
peer.removeChainDownloadStartedEventListener(peerDataEventListener);
peer.removeGetDataEventListener(peerDataEventListener);
peer.removePreMessageReceivedEventListener(peerDataEventListener);
}
public void downloadBlockChain() {
DownloadProgressTracker downloadProgressTracker = new DownloadProgressTracker();
startBlockChainDownload(downloadProgressTracker);
try {
downloadProgressTracker.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
protected void handleNewPeer(final Peer peer) {
this.lock.lock();
try {
this.groupBackoff.trackSuccess();
this.backoffMap.get(peer.getAddress()).trackSuccess();
this.pendingPeers.remove(peer);
this.peers.add(peer);
final int size = this.peers.size();
boolean z = false;
log.info("{}: New peer ({} connected, {} pending, {} max)", peer, Integer.valueOf(size), Integer.valueOf(this.pendingPeers.size()), Integer.valueOf(this.maxConnections));
if (this.bloomFilterMerger.getLastFilter() != null) {
peer.setBloomFilter(this.bloomFilterMerger.getLastFilter());
}
peer.setDownloadData(false);
Iterator<Wallet> it = this.wallets.iterator();
while (it.hasNext()) {
peer.addWallet(it.next());
}
if (this.downloadPeer == null) {
setDownloadPeer(selectDownloadPeer(this.peers));
if (this.downloadListener != null && this.chain != null) {
z = true;
}
if (z) {
startBlockChainDownloadFromPeer(this.downloadPeer);
}
}
peer.addBlocksDownloadedEventListener(Threading.SAME_THREAD, this.peerListener);
peer.addGetDataEventListener(Threading.SAME_THREAD, this.peerListener);
Iterator<ListenerRegistration<BlocksDownloadedEventListener>> it2 = this.peersBlocksDownloadedEventListeners.iterator();
while (it2.hasNext()) {
ListenerRegistration<BlocksDownloadedEventListener> next = it2.next();
peer.addBlocksDownloadedEventListener(next.executor, next.listener);
}
Iterator<ListenerRegistration<ChainDownloadStartedEventListener>> it3 = this.peersChainDownloadStartedEventListeners.iterator();
while (it3.hasNext()) {
ListenerRegistration<ChainDownloadStartedEventListener> next2 = it3.next();
peer.addChainDownloadStartedEventListener(next2.executor, next2.listener);
}
Iterator<ListenerRegistration<PeerConnectedEventListener>> it4 = this.peerConnectedEventListeners.iterator();
while (it4.hasNext()) {
ListenerRegistration<PeerConnectedEventListener> next3 = it4.next();
peer.addConnectedEventListener(next3.executor, next3.listener);
}
Iterator<ListenerRegistration<GetDataEventListener>> it5 = this.peerGetDataEventListeners.iterator();
while (it5.hasNext()) {
ListenerRegistration<GetDataEventListener> next4 = it5.next();
peer.addGetDataEventListener(next4.executor, next4.listener);
}
Iterator<ListenerRegistration<OnTransactionBroadcastListener>> it6 = this.peersTransactionBroadastEventListeners.iterator();
while (it6.hasNext()) {
ListenerRegistration<OnTransactionBroadcastListener> next5 = it6.next();
peer.addOnTransactionBroadcastListener(next5.executor, next5.listener);
}
Iterator<ListenerRegistration<PreMessageReceivedEventListener>> it7 = this.peersPreMessageReceivedEventListeners.iterator();
while (it7.hasNext()) {
ListenerRegistration<PreMessageReceivedEventListener> next6 = it7.next();
peer.addPreMessageReceivedEventListener(next6.executor, next6.listener);
}
this.lock.unlock();
Iterator<ListenerRegistration<PeerConnectedEventListener>> it8 = this.peerConnectedEventListeners.iterator();
while (it8.hasNext()) {
final ListenerRegistration<PeerConnectedEventListener> next7 = it8.next();
next7.executor.execute(new Runnable() {
@Override
public void run() {
((PeerConnectedEventListener) next7.listener).onPeerConnected(peer, size);
}
});
}
} catch (Throwable th) {
this.lock.unlock();
throw th;
}
}
public void setupPinging() {
if (getPingIntervalMsec() <= 0) {
return;
}
this.vPingTask = this.executor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
if (PeerGroup.this.getPingIntervalMsec() <= 0) {
ListenableScheduledFuture listenableScheduledFuture = PeerGroup.this.vPingTask;
if (listenableScheduledFuture != null) {
listenableScheduledFuture.cancel(false);
PeerGroup.this.vPingTask = null;
return;
}
return;
}
for (Peer peer : PeerGroup.this.getConnectedPeers()) {
if (peer.getPeerVersionMessage().clientVersion >= PeerGroup.this.params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.PONG)) {
peer.ping();
}
}
} catch (Throwable th) {
PeerGroup.log.error("Exception in ping loop", th);
}
}
}, getPingIntervalMsec(), getPingIntervalMsec(), TimeUnit.MILLISECONDS);
}
private void setDownloadPeer(@Nullable Peer peer) {
this.lock.lock();
try {
if (this.downloadPeer == peer) {
return;
}
if (this.downloadPeer != null) {
log.info("Unsetting download peer: {}", this.downloadPeer);
if (this.downloadListener != null) {
removeDataEventListenerFromPeer(this.downloadPeer, this.downloadListener);
}
this.downloadPeer.setDownloadData(false);
}
this.downloadPeer = peer;
if (peer != null) {
log.info("Setting download peer: {}", peer);
if (this.downloadListener != null) {
addDataEventListenerToPeer(Threading.SAME_THREAD, peer, this.downloadListener);
}
this.downloadPeer.setDownloadData(true);
if (this.chain != null) {
this.downloadPeer.setDownloadParameters(this.fastCatchupTimeSecs, this.bloomFilterMerger.getLastFilter() != null);
}
}
} finally {
this.lock.unlock();
}
}
@Nullable
@Deprecated
public TxConfidenceTable getMemoryPool() {
return Context.get().getConfidenceTable();
}
public void setFastCatchupTimeSecs(long j) {
boolean z;
this.lock.lock();
try {
if (this.chain != null && this.chain.shouldVerifyTransactions()) {
z = false;
Preconditions.checkState(z, "Fast catchup is incompatible with fully verifying");
this.fastCatchupTimeSecs = j;
if (this.downloadPeer != null) {
this.downloadPeer.setDownloadParameters(j, this.bloomFilterMerger.getLastFilter() != null);
}
}
z = true;
Preconditions.checkState(z, "Fast catchup is incompatible with fully verifying");
this.fastCatchupTimeSecs = j;
if (this.downloadPeer != null) {
}
} finally {
this.lock.unlock();
}
}
public long getFastCatchupTimeSecs() {
this.lock.lock();
try {
return this.fastCatchupTimeSecs;
} finally {
this.lock.unlock();
}
}
protected void handlePeerDeath(final Peer peer, @Nullable Throwable th) {
if (isRunning()) {
this.lock.lock();
try {
this.pendingPeers.remove(peer);
this.peers.remove(peer);
PeerAddress address = peer.getAddress();
log.info("{}: Peer died ({} connected, {} pending, {} max)", address, Integer.valueOf(this.peers.size()), Integer.valueOf(this.pendingPeers.size()), Integer.valueOf(this.maxConnections));
if (peer == this.downloadPeer) {
log.info("Download peer died. Picking a new one.");
setDownloadPeer(null);
Peer selectDownloadPeer = selectDownloadPeer(this.peers);
if (selectDownloadPeer != null) {
setDownloadPeer(selectDownloadPeer);
if (this.downloadListener != null) {
startBlockChainDownloadFromPeer(selectDownloadPeer);
}
}
}
int size = this.peers.size() + this.pendingPeers.size();
final int size2 = this.peers.size();
this.groupBackoff.trackFailure();
if (th instanceof NoRouteToHostException) {
if ((address.getAddr() instanceof Inet6Address) && !this.ipv6Unreachable) {
this.ipv6Unreachable = true;
log.warn("IPv6 peer connect failed due to routing failure, ignoring IPv6 addresses from now on");
}
} else {
this.backoffMap.get(address).trackFailure();
this.inactives.offer(address);
}
if (size < getMaxConnections()) {
triggerConnections();
}
this.lock.unlock();
peer.removeBlocksDownloadedEventListener(this.peerListener);
peer.removeGetDataEventListener(this.peerListener);
Iterator<Wallet> it = this.wallets.iterator();
while (it.hasNext()) {
peer.removeWallet(it.next());
}
Iterator<ListenerRegistration<BlocksDownloadedEventListener>> it2 = this.peersBlocksDownloadedEventListeners.iterator();
while (it2.hasNext()) {
peer.removeBlocksDownloadedEventListener(it2.next().listener);
}
Iterator<ListenerRegistration<ChainDownloadStartedEventListener>> it3 = this.peersChainDownloadStartedEventListeners.iterator();
while (it3.hasNext()) {
peer.removeChainDownloadStartedEventListener(it3.next().listener);
}
Iterator<ListenerRegistration<GetDataEventListener>> it4 = this.peerGetDataEventListeners.iterator();
while (it4.hasNext()) {
peer.removeGetDataEventListener(it4.next().listener);
}
Iterator<ListenerRegistration<PreMessageReceivedEventListener>> it5 = this.peersPreMessageReceivedEventListeners.iterator();
while (it5.hasNext()) {
peer.removePreMessageReceivedEventListener(it5.next().listener);
}
Iterator<ListenerRegistration<OnTransactionBroadcastListener>> it6 = this.peersTransactionBroadastEventListeners.iterator();
while (it6.hasNext()) {
peer.removeOnTransactionBroadcastListener(it6.next().listener);
}
Iterator<ListenerRegistration<PeerDisconnectedEventListener>> it7 = this.peerDisconnectedEventListeners.iterator();
while (it7.hasNext()) {
final ListenerRegistration<PeerDisconnectedEventListener> next = it7.next();
next.executor.execute(new Runnable() {
@Override
public void run() {
((PeerDisconnectedEventListener) next.listener).onPeerDisconnected(peer, size2);
}
});
peer.removeDisconnectedEventListener(next.listener);
}
} catch (Throwable th2) {
this.lock.unlock();
throw th2;
}
}
}
public void setStallThreshold(int i, int i2) {
this.lock.lock();
try {
this.stallPeriodSeconds = i;
this.stallMinSpeedBytesSec = i2;
} finally {
this.lock.unlock();
}
}
public class ChainDownloadSpeedCalculator implements BlocksDownloadedEventListener, Runnable {
private int blocksInLastSecond;
private long bytesInLastSecond;
private int cursor;
private int maxStalls;
private int origTxnsInLastSecond;
private long[] samples;
private boolean syncDone;
private int txnsInLastSecond;
private int warmupSeconds;
private ChainDownloadSpeedCalculator() {
this.maxStalls = 3;
this.warmupSeconds = -1;
}
@Override
public synchronized void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int i) {
this.blocksInLastSecond++;
this.bytesInLastSecond += 80;
List<Transaction> transactions = block.getTransactions();
this.txnsInLastSecond += (transactions != null ? countAndMeasureSize(transactions) : 0) + (filteredBlock != null ? countAndMeasureSize(filteredBlock.getAssociatedTransactions().values()) : 0);
if (filteredBlock != null) {
this.origTxnsInLastSecond += filteredBlock.getTransactionCount();
}
}
private int countAndMeasureSize(Collection<Transaction> collection) {
Iterator<Transaction> it = collection.iterator();
while (it.hasNext()) {
this.bytesInLastSecond += it.next().getMessageSize();
}
return collection.size();
}
@Override
public void run() {
try {
calculate();
} catch (Throwable th) {
PeerGroup.log.error("Error in speed calculator", th);
}
}
private void calculate() {
PeerGroup.this.lock.lock();
try {
int i = PeerGroup.this.stallMinSpeedBytesSec;
int i2 = PeerGroup.this.stallPeriodSeconds;
synchronized (this) {
if (this.samples == null || this.samples.length != i2) {
long[] jArr = new long[i2];
this.samples = jArr;
Arrays.fill(jArr, i * 2);
this.warmupSeconds = 15;
}
if (!(PeerGroup.this.chain != null && PeerGroup.this.chain.getBestChainHeight() < PeerGroup.this.getMostCommonChainHeight())) {
this.syncDone = true;
}
if (!this.syncDone) {
if (this.warmupSeconds < 0) {
long[] jArr2 = this.samples;
int i3 = this.cursor;
int i4 = i3 + 1;
this.cursor = i4;
jArr2[i3] = this.bytesInLastSecond;
if (i4 == this.samples.length) {
this.cursor = 0;
}
long j = 0;
for (long j2 : this.samples) {
j += j2;
}
long length = j / this.samples.length;
double d = length / 1024.0d;
double d2 = i / 1024.0d;
PeerGroup.log.info(String.format(Locale.US, "%d blocks/sec, %d tx/sec, %d pre-filtered tx/sec, avg/last %.2f/%.2f kilobytes per sec (stall threshold <%.2f KB/sec for %d seconds)", Integer.valueOf(this.blocksInLastSecond), Integer.valueOf(this.txnsInLastSecond), Integer.valueOf(this.origTxnsInLastSecond), Double.valueOf(d), Double.valueOf(this.bytesInLastSecond / 1024.0d), Double.valueOf(d2), Integer.valueOf(this.samples.length)));
if (length < i && this.maxStalls > 0) {
int i5 = this.maxStalls - 1;
this.maxStalls = i5;
if (i5 == 0) {
PeerGroup.log.warn("This network seems to be slower than the requested stall threshold - won't do stall disconnects any more.");
} else {
Peer downloadPeer = PeerGroup.this.getDownloadPeer();
PeerGroup.log.warn(String.format(Locale.US, "Chain download stalled: received %.2f KB/sec for %d seconds, require average of %.2f KB/sec, disconnecting %s", Double.valueOf(d), Integer.valueOf(this.samples.length), Double.valueOf(d2), downloadPeer));
downloadPeer.close();
this.samples = null;
this.warmupSeconds = i2;
}
}
} else {
this.warmupSeconds--;
if (this.bytesInLastSecond > 0) {
PeerGroup.log.info(String.format(Locale.US, "%d blocks/sec, %d tx/sec, %d pre-filtered tx/sec, last %.2f kilobytes per sec", Integer.valueOf(this.blocksInLastSecond), Integer.valueOf(this.txnsInLastSecond), Integer.valueOf(this.origTxnsInLastSecond), Double.valueOf(this.bytesInLastSecond / 1024.0d)));
}
}
}
this.blocksInLastSecond = 0;
this.txnsInLastSecond = 0;
this.origTxnsInLastSecond = 0;
this.bytesInLastSecond = 0L;
}
} finally {
PeerGroup.this.lock.unlock();
}
}
}
private void startBlockChainDownloadFromPeer(Peer peer) {
this.lock.lock();
try {
setDownloadPeer(peer);
if (this.chainDownloadSpeedCalculator == null) {
ChainDownloadSpeedCalculator chainDownloadSpeedCalculator = new ChainDownloadSpeedCalculator();
this.chainDownloadSpeedCalculator = chainDownloadSpeedCalculator;
this.executor.scheduleAtFixedRate((Runnable) chainDownloadSpeedCalculator, 1L, 1L, TimeUnit.SECONDS);
}
peer.addBlocksDownloadedEventListener(Threading.SAME_THREAD, this.chainDownloadSpeedCalculator);
peer.startBlockChainDownload();
} finally {
this.lock.unlock();
}
}
public ListenableFuture<List<Peer>> waitForPeers(int i) {
return waitForPeersOfVersion(i, 0L);
}
public ListenableFuture<List<Peer>> waitForPeersOfVersion(final int i, final long j) {
List<Peer> findPeersOfAtLeastVersion = findPeersOfAtLeastVersion(j);
if (findPeersOfAtLeastVersion.size() >= i) {
return Futures.immediateFuture(findPeersOfAtLeastVersion);
}
final SettableFuture create = SettableFuture.create();
addConnectedEventListener(new PeerConnectedEventListener() {
@Override
public void onPeerConnected(Peer peer, int i2) {
List<Peer> findPeersOfAtLeastVersion2 = PeerGroup.this.findPeersOfAtLeastVersion(j);
if (findPeersOfAtLeastVersion2.size() >= i) {
create.set(findPeersOfAtLeastVersion2);
PeerGroup.this.removeConnectedEventListener(this);
}
}
});
return create;
}
public List<Peer> findPeersOfAtLeastVersion(long j) {
this.lock.lock();
try {
ArrayList arrayList = new ArrayList(this.peers.size());
Iterator<Peer> it = this.peers.iterator();
while (it.hasNext()) {
Peer next = it.next();
if (next.getPeerVersionMessage().clientVersion >= j) {
arrayList.add(next);
}
}
return arrayList;
} finally {
this.lock.unlock();
}
}
public ListenableFuture<List<Peer>> waitForPeersWithServiceMask(final int i, final int i2) {
this.lock.lock();
try {
List<Peer> findPeersWithServiceMask = findPeersWithServiceMask(i2);
if (findPeersWithServiceMask.size() >= i) {
return Futures.immediateFuture(findPeersWithServiceMask);
}
final SettableFuture create = SettableFuture.create();
addConnectedEventListener(new PeerConnectedEventListener() {
@Override
public void onPeerConnected(Peer peer, int i3) {
List<Peer> findPeersWithServiceMask2 = PeerGroup.this.findPeersWithServiceMask(i2);
if (findPeersWithServiceMask2.size() >= i) {
create.set(findPeersWithServiceMask2);
PeerGroup.this.removeConnectedEventListener(this);
}
}
});
return create;
} finally {
this.lock.unlock();
}
}
public List<Peer> findPeersWithServiceMask(int i) {
this.lock.lock();
try {
ArrayList arrayList = new ArrayList(this.peers.size());
Iterator<Peer> it = this.peers.iterator();
while (it.hasNext()) {
Peer next = it.next();
long j = i;
if ((next.getPeerVersionMessage().localServices & j) == j) {
arrayList.add(next);
}
}
return arrayList;
} finally {
this.lock.unlock();
}
}
public int getMinBroadcastConnections() {
int i;
this.lock.lock();
try {
if (this.minBroadcastConnections == 0) {
i = getMaxConnections();
if (i > 1) {
return (int) Math.round(getMaxConnections() * 0.8d);
}
} else {
i = this.minBroadcastConnections;
}
return i;
} finally {
this.lock.unlock();
}
}
public void setMinBroadcastConnections(int i) {
this.lock.lock();
try {
this.minBroadcastConnections = i;
} finally {
this.lock.unlock();
}
}
@Override
public TransactionBroadcast broadcastTransaction(Transaction transaction) {
return broadcastTransaction(transaction, Math.max(1, getMinBroadcastConnections()));
}
public TransactionBroadcast broadcastTransaction(Transaction transaction, int i) {
if (transaction.getConfidence().getSource().equals(TransactionConfidence.Source.UNKNOWN)) {
log.info("Transaction source unknown, setting to SELF: {}", transaction.getHashAsString());
transaction.getConfidence().setSource(TransactionConfidence.Source.SELF);
}
final TransactionBroadcast transactionBroadcast = new TransactionBroadcast(this, transaction);
transactionBroadcast.setMinConnections(i);
Futures.addCallback(transactionBroadcast.future(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction2) {
PeerGroup.this.runningBroadcasts.remove(transactionBroadcast);
Iterator it = PeerGroup.this.wallets.iterator();
while (it.hasNext()) {
try {
((Wallet) it.next()).receivePending(transaction2, null);
} catch (VerificationException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void onFailure(Throwable th) {
PeerGroup.this.runningBroadcasts.remove(transactionBroadcast);
}
});
this.runningBroadcasts.add(transactionBroadcast);
transactionBroadcast.broadcast();
return transactionBroadcast;
}
public long getPingIntervalMsec() {
this.lock.lock();
try {
return this.pingIntervalMsec;
} finally {
this.lock.unlock();
}
}
public void setPingIntervalMsec(long j) {
this.lock.lock();
try {
this.pingIntervalMsec = j;
ListenableScheduledFuture<?> listenableScheduledFuture = this.vPingTask;
if (listenableScheduledFuture != null) {
listenableScheduledFuture.cancel(false);
}
setupPinging();
} finally {
this.lock.unlock();
}
}
public void setMinRequiredProtocolVersion(int i) {
this.vMinRequiredProtocolVersion = i;
}
public int getMinRequiredProtocolVersion() {
return this.vMinRequiredProtocolVersion;
}
public int getMostCommonChainHeight() {
this.lock.lock();
try {
return getMostCommonChainHeight(this.peers);
} finally {
this.lock.unlock();
}
}
public static int getMostCommonChainHeight(List<Peer> list) {
if (list.isEmpty()) {
return 0;
}
ArrayList arrayList = new ArrayList(list.size());
Iterator<Peer> it = list.iterator();
while (it.hasNext()) {
arrayList.add(Integer.valueOf((int) it.next().getBestHeight()));
}
return Utils.maxOfMostFreq(arrayList);
}
@Nullable
protected Peer selectDownloadPeer(List<Peer> list) {
if (list.isEmpty()) {
return null;
}
int mostCommonChainHeight = getMostCommonChainHeight(list);
ArrayList<Peer> arrayList = new ArrayList();
for (Peer peer : list) {
if (peer.getBestHeight() == mostCommonChainHeight) {
arrayList.add(peer);
}
}
int protocolVersionNum = this.params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.BLOOM_FILTER);
Iterator it = arrayList.iterator();
int i = 0;
int i2 = 0;
while (it.hasNext()) {
i = Math.max(((Peer) it.next()).getPeerVersionMessage().clientVersion, i);
i2 = Math.min(i, protocolVersionNum);
}
ArrayList arrayList2 = new ArrayList(arrayList.size());
for (Peer peer2 : arrayList) {
if (peer2.getPeerVersionMessage().clientVersion >= i2) {
arrayList2.add(peer2);
}
}
return (Peer) arrayList2.get((int) (Math.random() * arrayList2.size()));
}
public Peer getDownloadPeer() {
this.lock.lock();
try {
return this.downloadPeer;
} finally {
this.lock.unlock();
}
}
@Nullable
public TorClient getTorClient() {
return this.torClient;
}
public int getMaxPeersToDiscoverCount() {
return this.vMaxPeersToDiscoverCount;
}
public void setMaxPeersToDiscoverCount(int i) {
this.vMaxPeersToDiscoverCount = i;
}
public boolean getUseLocalhostPeerWhenPossible() {
this.lock.lock();
try {
return this.useLocalhostPeerWhenPossible;
} finally {
this.lock.unlock();
}
}
public void setUseLocalhostPeerWhenPossible(boolean z) {
this.lock.lock();
try {
this.useLocalhostPeerWhenPossible = z;
} finally {
this.lock.unlock();
}
}
public boolean isRunning() {
return this.vRunning;
}
public void setBloomFilteringEnabled(boolean z) {
this.vBloomFilteringEnabled = z;
}
public boolean isBloomFilteringEnabled() {
return this.vBloomFilteringEnabled;
}
}