diff --git a/core/src/main/java/org/bitcoinj/core/PeerGroup.java b/core/src/main/java/org/bitcoinj/core/PeerGroup.java index 436acf64..23ba232b 100644 --- a/core/src/main/java/org/bitcoinj/core/PeerGroup.java +++ b/core/src/main/java/org/bitcoinj/core/PeerGroup.java @@ -1464,12 +1464,33 @@ public class PeerGroup implements TransactionBroadcaster { } } + @GuardedBy("lock") private int stallPeriodSeconds = 10; + @GuardedBy("lock") private int stallMinSpeed = 15; + + /** + * Configures the stall speed: the speed at which a peer is considered to be serving us the block chain + * unacceptably slowly. Once a peer has served us slower than the given "blocks per second" for the given + * number of seconds, it is considered stalled and will be disconnected, forcing the chain download to be + * restarted from a different peer. The defaults are chosen to work well for regular wallets and platforms, + * but if you are running on a platform that is CPU constrained the default settings may need adjustment to + * avoid false stalls. + * + * @param periodSecs How many seconds the download speed must be below blocksPerSec, defaults to 10. + * @param blocksPerSec How many blocks per second the speed must be consistently below, defaults to 10. + */ + public void setStallThreshold(int periodSecs, int blocksPerSec) { + lock.lock(); + try { + stallPeriodSeconds = periodSecs; + stallMinSpeed = blocksPerSec; + } finally { + lock.unlock(); + } + } + private class ChainDownloadSpeedCalculator extends AbstractPeerEventListener implements Runnable { private int blocksInLastSecond, txnsInLastSecond, origTxnsInLastSecond, stallWarning; - private static final int STALL_PERIOD_SECONDS = 15; - private static final int STALL_MIN_SPEED = 5; - @Override public synchronized void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) { blocksInLastSecond++; @@ -1483,24 +1504,37 @@ public class PeerGroup implements TransactionBroadcaster { } @Override - public synchronized void run() { - if (blocksInLastSecond > 0) { - log.info("{} blocks/sec, {} tx/sec, {} pre-filtered tx/sec", blocksInLastSecond, txnsInLastSecond, origTxnsInLastSecond); - if (blocksInLastSecond >= STALL_MIN_SPEED) - stallWarning = 0; + public void run() { + int period; + int minSpeed; + + lock.lock(); + try { + period = stallPeriodSeconds; + minSpeed = stallMinSpeed; + } finally { + lock.unlock(); } - if (chain != null && chain.getBestChainHeight() < getMostCommonChainHeight() && blocksInLastSecond < STALL_MIN_SPEED && stallWarning > -1) { - stallWarning++; - if (stallWarning == STALL_PERIOD_SECONDS) { - stallWarning = -1; - Peer peer = getDownloadPeer(); - log.warn("Chain download stalled: slow progress for {} seconds, disconnecting {}", STALL_PERIOD_SECONDS, peer); - peer.close(); + + synchronized (this) { + if (blocksInLastSecond > 0) { + log.info("{} blocks/sec, {} tx/sec, {} pre-filtered tx/sec", blocksInLastSecond, txnsInLastSecond, origTxnsInLastSecond); + if (blocksInLastSecond >= period) + stallWarning = 0; } + if (chain != null && chain.getBestChainHeight() < getMostCommonChainHeight() && blocksInLastSecond < minSpeed && stallWarning > -1) { + stallWarning++; + if (stallWarning == minSpeed) { + stallWarning = -1; + Peer peer = getDownloadPeer(); + log.warn("Chain download stalled: slow progress for {} seconds, disconnecting {}", period, peer); + peer.close(); + } + } + blocksInLastSecond = 0; + txnsInLastSecond = 0; + origTxnsInLastSecond = 0; } - blocksInLastSecond = 0; - txnsInLastSecond = 0; - origTxnsInLastSecond = 0; } } @Nullable private ChainDownloadSpeedCalculator chainDownloadSpeedCalculator;