forked from PegaSysEng/pantheon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch to new sync target if it exceeds the td threshold (PegaSysEng#…
…1286) Increase total difficulty threshold required to switch sync targets. Increase threshold for changing sync target based on height to 200.
- Loading branch information
Showing
5 changed files
with
232 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
...main/java/tech/pegasys/pantheon/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Copyright 2019 ConsenSys AG. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations under the License. | ||
*/ | ||
package tech.pegasys.pantheon.ethereum.eth.sync.fullsync; | ||
|
||
import tech.pegasys.pantheon.ethereum.eth.manager.ChainState; | ||
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; | ||
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeers; | ||
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; | ||
import tech.pegasys.pantheon.util.uint.UInt256; | ||
|
||
import java.util.Optional; | ||
|
||
public class BetterSyncTargetEvaluator { | ||
|
||
private final SynchronizerConfiguration config; | ||
private final EthPeers ethPeers; | ||
|
||
public BetterSyncTargetEvaluator( | ||
final SynchronizerConfiguration config, final EthPeers ethPeers) { | ||
this.config = config; | ||
this.ethPeers = ethPeers; | ||
} | ||
|
||
public boolean shouldSwitchSyncTarget(final EthPeer currentSyncTarget) { | ||
final ChainState currentPeerChainState = currentSyncTarget.chainState(); | ||
final Optional<EthPeer> maybeBestPeer = ethPeers.bestPeer(); | ||
|
||
return maybeBestPeer | ||
.map( | ||
bestPeer -> { | ||
if (EthPeers.BEST_CHAIN.compare(bestPeer, currentSyncTarget) <= 0) { | ||
// Our current target is better or equal to the best peer | ||
return false; | ||
} | ||
// Require some threshold to be exceeded before switching targets to keep some | ||
// stability when multiple peers are in range of each other | ||
final ChainState bestPeerChainState = bestPeer.chainState(); | ||
final UInt256 tdDifference = | ||
bestPeerChainState | ||
.getBestBlock() | ||
.getTotalDifficulty() | ||
.minus(currentPeerChainState.getBestBlock().getTotalDifficulty()); | ||
if (tdDifference.compareTo(config.downloaderChangeTargetThresholdByTd()) > 0) { | ||
return true; | ||
} | ||
final long heightDifference = | ||
bestPeerChainState.getEstimatedHeight() | ||
- currentPeerChainState.getEstimatedHeight(); | ||
return heightDifference > config.downloaderChangeTargetThresholdByHeight(); | ||
}) | ||
.orElse(false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
157 changes: 157 additions & 0 deletions
157
.../java/tech/pegasys/pantheon/ethereum/eth/sync/fullsync/BetterSyncTargetEvaluatorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/* | ||
* Copyright 2019 ConsenSys AG. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations under the License. | ||
*/ | ||
package tech.pegasys.pantheon.ethereum.eth.sync.fullsync; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.when; | ||
|
||
import tech.pegasys.pantheon.ethereum.core.Hash; | ||
import tech.pegasys.pantheon.ethereum.eth.manager.ChainState; | ||
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; | ||
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeers; | ||
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; | ||
import tech.pegasys.pantheon.util.uint.UInt256; | ||
|
||
import java.util.Optional; | ||
|
||
import org.junit.Test; | ||
|
||
public class BetterSyncTargetEvaluatorTest { | ||
|
||
private static final int CURRENT_TARGET_HEIGHT = 10; | ||
private static final int CURRENT_TARGET_TD = 50; | ||
private static final int HEIGHT_THRESHOLD = 100; | ||
private static final int TD_THRESHOLD = 5; | ||
private final EthPeers ethPeers = mock(EthPeers.class); | ||
private final EthPeer currentTarget = peer(CURRENT_TARGET_HEIGHT, CURRENT_TARGET_TD); | ||
private final BetterSyncTargetEvaluator evaluator = | ||
new BetterSyncTargetEvaluator( | ||
SynchronizerConfiguration.builder() | ||
.downloaderChangeTargetThresholdByHeight(HEIGHT_THRESHOLD) | ||
.downloaderChangeTargetThresholdByTd(UInt256.of(TD_THRESHOLD)) | ||
.build(), | ||
ethPeers); | ||
|
||
@Test | ||
public void shouldNotSwitchTargetsIfNoBestPeerIsAvailable() { | ||
when(ethPeers.bestPeer()).thenReturn(Optional.empty()); | ||
|
||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchTargetWhenBestPeerHasLowerHeightAndDifficulty() { | ||
bestPeerWithDelta(-1, -1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchTargetWhenBestPeerHasSameHeightAndLowerDifficulty() { | ||
bestPeerWithDelta(0, -1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchTargetWhenBestPeerHasLowerHeightAndSameDifficulty() { | ||
bestPeerWithDelta(-1, 0); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchTargetWhenBestPeerHasGreaterHeightAndLowerDifficulty() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD + 1, -1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchTargetWhenBestPeerHasEqualHeightAndDifficulty() { | ||
bestPeerWithDelta(0, 0); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchWhenHeightAndTdHigherWithinThreshold() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD - 1, TD_THRESHOLD - 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchWhenHeightAndTdHigherEqualToThreshold() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD, TD_THRESHOLD); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenHeightExceedsThresholdAndDifficultyEqual() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD + 1, 0); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenHeightExceedsThresholdAndDifficultyWithinThreshold() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD + 1, TD_THRESHOLD - 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenHeightAndDifficultyExceedThreshold() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD + 1, TD_THRESHOLD + 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
@Test | ||
public void shouldNotSwitchWhenHeightExceedsThresholdButDifficultyIsLower() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD + 1, -1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isFalse(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenDifficultyExceedsThresholdAndHeightIsEqual() { | ||
bestPeerWithDelta(0, TD_THRESHOLD + 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenDifficultyExceedsThresholdAndHeightIsLower() { | ||
bestPeerWithDelta(-1, TD_THRESHOLD + 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenDifficultyExceedsThresholdAndHeightIsWithinThreshold() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD - 1, TD_THRESHOLD + 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
@Test | ||
public void shouldSwitchWhenHeightAndDifficultyExceedsThreshold() { | ||
bestPeerWithDelta(HEIGHT_THRESHOLD + 1, TD_THRESHOLD + 1); | ||
assertThat(evaluator.shouldSwitchSyncTarget(currentTarget)).isTrue(); | ||
} | ||
|
||
private void bestPeerWithDelta(final long height, final long totalDifficulty) { | ||
final EthPeer bestPeer = | ||
peer(CURRENT_TARGET_HEIGHT + height, CURRENT_TARGET_TD + totalDifficulty); | ||
when(ethPeers.bestPeer()).thenReturn(Optional.of(bestPeer)); | ||
} | ||
|
||
private EthPeer peer(final long chainHeight, final long totalDifficulty) { | ||
final EthPeer peer = mock(EthPeer.class); | ||
final ChainState chainState = new ChainState(); | ||
chainState.updateHeightEstimate(chainHeight); | ||
chainState.statusReceived(Hash.EMPTY, UInt256.of(totalDifficulty)); | ||
when(peer.chainState()).thenReturn(chainState); | ||
return peer; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters