[NC-1384] Disable mining while catching up to chain head (#125)

Adrian Sutton 6 years ago committed by GitHub
parent ba18fcf163
commit d2583e3ef2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      acceptance-tests/build.gradle
  2. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNode.java
  3. 2
      acceptance-tests/src/test/java/tech/pegasys/pantheon/tests/acceptance/dsl/node/PantheonNodeConfig.java
  4. 1
      consensus/clique/build.gradle
  5. 2
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java
  6. 4
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutor.java
  7. 14
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMiningCoordinator.java
  8. 2
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java
  9. 1
      consensus/ibft/build.gradle
  10. 2
      consensus/ibft/src/main/java/tech/pegasys/pantheon/consensus/ibft/blockcreation/IbftBlockMiner.java
  11. 1
      consensus/ibftlegacy/build.gradle
  12. 27
      ethereum/blockcreation/build.gradle
  13. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractBlockCreator.java
  14. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractBlockScheduler.java
  15. 3
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMinerExecutor.java
  16. 65
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMiningCoordinator.java
  17. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/AsyncBlockCreator.java
  18. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockCreator.java
  19. 2
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockMiner.java
  20. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelector.java
  21. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/CoinbaseNotSetException.java
  22. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/DefaultBlockScheduler.java
  23. 9
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreator.java
  24. 3
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockMiner.java
  25. 4
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutor.java
  26. 6
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java
  27. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/IncrementingNonceGenerator.java
  28. 0
      ethereum/blockcreation/src/main/java/tech/pegasys/pantheon/ethereum/blockcreation/RandomNonceGenerator.java
  29. 138
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/AbstractMiningCoordinatorTest.java
  30. 3
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockMinerTest.java
  31. 0
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/BlockTransactionSelectorTest.java
  32. 0
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/DefaultBlockSchedulerTest.java
  33. 8
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java
  34. 1
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMinerExecutorTest.java
  35. 21
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashMiningCoordinatorTest.java
  36. 0
      ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/IncrementingNonceGeneratorTest.java
  37. 4
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/BlockAddedEvent.java
  38. 19
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/MinedBlockObserver.java
  39. 4
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/MiningParameters.java
  40. 1
      ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/MiningParametersTestBuilder.java
  41. 19
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/ChainState.java
  42. 9
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthPeer.java
  43. 2
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManager.java
  44. 5
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManager.java
  45. 13
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/DefaultSynchronizer.java
  46. 10
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/Downloader.java
  47. 3
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/TrailingPeerLimiter.java
  48. 84
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/state/SyncState.java
  49. 17
      ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/state/SyncTarget.java
  50. 59
      ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ChainStateTest.java
  51. 15
      ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java
  52. 3
      ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/DownloaderTest.java
  53. 114
      ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/state/SyncStateTest.java
  54. 1
      ethereum/jsonrpc/build.gradle
  55. 1
      pantheon/build.gradle
  56. 2
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java
  57. 3
      pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonControllerBuilder.java
  58. 18
      pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java
  59. 14
      pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java
  60. 16
      pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java
  61. 3
      pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java
  62. 3
      pantheon/src/test/java/tech/pegasys/pantheon/RunnerTest.java
  63. 2
      pantheon/src/test/java/tech/pegasys/pantheon/cli/PantheonCommandTest.java
  64. 3
      pantheon/src/test/java/tech/pegasys/pantheon/util/BlockchainImporterTest.java
  65. 1
      settings.gradle

@ -19,6 +19,7 @@ dependencies {
testImplementation project(':crypto') testImplementation project(':crypto')
testImplementation project(':ethereum:eth') testImplementation project(':ethereum:eth')
testImplementation project(':ethereum:core') testImplementation project(':ethereum:core')
testImplementation project(':ethereum:blockcreation')
testImplementation project(':ethereum:jsonrpc') testImplementation project(':ethereum:jsonrpc')
testImplementation project(':pantheon') testImplementation project(':pantheon')
testImplementation project(':util') testImplementation project(':util')

@ -19,7 +19,7 @@ import static org.web3j.protocol.core.DefaultBlockParameterName.LATEST;
import tech.pegasys.pantheon.controller.KeyPairUtil; import tech.pegasys.pantheon.controller.KeyPairUtil;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters; import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
import tech.pegasys.pantheon.tests.acceptance.dsl.account.Account; import tech.pegasys.pantheon.tests.acceptance.dsl.account.Account;

@ -12,7 +12,7 @@
*/ */
package tech.pegasys.pantheon.tests.acceptance.dsl.node; package tech.pegasys.pantheon.tests.acceptance.dsl.node;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters; import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi;

@ -26,6 +26,7 @@ repositories { mavenCentral() }
dependencies { dependencies {
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation')
implementation project(':ethereum:eth') implementation project(':ethereum:eth')
implementation project(':ethereum:jsonrpc') implementation project(':ethereum:jsonrpc')
implementation project(':ethereum:rlp') implementation project(':ethereum:rlp')

@ -16,8 +16,8 @@ import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueHelpers; import tech.pegasys.pantheon.consensus.clique.CliqueHelpers;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.blockcreation.BlockMiner; import tech.pegasys.pantheon.ethereum.blockcreation.BlockMiner;
import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;

@ -20,10 +20,10 @@ import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMinerExecutor; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMinerExecutor;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;

@ -15,19 +15,13 @@ package tech.pegasys.pantheon.consensus.clique.blockcreation;
import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import java.util.Optional;
public class CliqueMiningCoordinator public class CliqueMiningCoordinator
extends AbstractMiningCoordinator<CliqueContext, CliqueBlockMiner> { extends AbstractMiningCoordinator<CliqueContext, CliqueBlockMiner> {
public CliqueMiningCoordinator(final Blockchain blockchain, final CliqueMinerExecutor executor) { public CliqueMiningCoordinator(
super(blockchain, executor); final Blockchain blockchain, final CliqueMinerExecutor executor, final SyncState syncState) {
} super(blockchain, executor, syncState);
@Override
protected void haltCurrentMiningOperation() {
currentRunningMiner.ifPresent(CliqueBlockMiner::cancel);
currentRunningMiner = Optional.empty();
} }
} }

@ -26,11 +26,11 @@ import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.AddressHelpers; import tech.pegasys.pantheon.ethereum.core.AddressHelpers;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;

@ -25,6 +25,7 @@ dependencies {
implementation project(':consensus:common') implementation project(':consensus:common')
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation')
implementation project(':ethereum:eth') implementation project(':ethereum:eth')
implementation project(':ethereum:jsonrpc') implementation project(':ethereum:jsonrpc')
implementation project(':ethereum:rlp') implementation project(':ethereum:rlp')

@ -15,8 +15,8 @@ package tech.pegasys.pantheon.consensus.ibft.blockcreation;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockScheduler;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.blockcreation.BlockMiner; import tech.pegasys.pantheon.ethereum.blockcreation.BlockMiner;
import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.Subscribers;

@ -13,6 +13,7 @@ dependencies {
implementation project(':consensus:ibft') implementation project(':consensus:ibft')
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation')
implementation project(':ethereum:eth') implementation project(':ethereum:eth')
implementation project(':ethereum:jsonrpc') implementation project(':ethereum:jsonrpc')
implementation project(':ethereum:rlp') implementation project(':ethereum:rlp')

@ -0,0 +1,27 @@
apply plugin: 'java-library'
jar {
baseName 'pantheon-blockcreation'
manifest {
attributes('Implementation-Title': baseName,
'Implementation-Version': project.version)
}
}
dependencies {
implementation project(':ethereum:core')
implementation project(':ethereum:eth')
implementation project(':util')
implementation project(':crypto')
implementation project(':services:kvstore')
implementation 'io.vertx:vertx-core'
implementation 'com.google.guava:guava'
testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.awaitility:awaitility'
testImplementation 'org.mockito:mockito-core'
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts')
}

@ -13,8 +13,9 @@
package tech.pegasys.pantheon.ethereum.blockcreation; package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;

@ -12,14 +12,16 @@
*/ */
package tech.pegasys.pantheon.ethereum.blockcreation; package tech.pegasys.pantheon.ethereum.blockcreation;
import static org.apache.logging.log4j.LogManager.getLogger;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent; import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent.EventType;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver; import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs;
import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.Subscribers;
@ -27,22 +29,29 @@ import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.Optional; import java.util.Optional;
import org.apache.logging.log4j.Logger;
public abstract class AbstractMiningCoordinator< public abstract class AbstractMiningCoordinator<
C, M extends BlockMiner<C, ? extends AbstractBlockCreator<C>>> C, M extends BlockMiner<C, ? extends AbstractBlockCreator<C>>>
implements BlockAddedObserver { implements BlockAddedObserver {
private static final Logger LOG = getLogger();
protected boolean isEnabled = false; protected boolean isEnabled = false;
protected volatile Optional<M> currentRunningMiner = Optional.empty(); protected volatile Optional<M> currentRunningMiner = Optional.empty();
private final Subscribers<MinedBlockObserver> minedBlockObservers = new Subscribers<>(); private final Subscribers<MinedBlockObserver> minedBlockObservers = new Subscribers<>();
private final AbstractMinerExecutor<C, M> executor; private final AbstractMinerExecutor<C, M> executor;
protected final Blockchain blockchain; protected final Blockchain blockchain;
private final SyncState syncState;
public AbstractMiningCoordinator( public AbstractMiningCoordinator(
final Blockchain blockchain, final AbstractMinerExecutor<C, M> executor) { final Blockchain blockchain,
final AbstractMinerExecutor<C, M> executor,
final SyncState syncState) {
this.executor = executor; this.executor = executor;
this.blockchain = blockchain; this.blockchain = blockchain;
this.syncState = syncState;
this.blockchain.observeBlockAdded(this); this.blockchain.observeBlockAdded(this);
syncState.addInSyncListener(this::inSyncChanged);
} }
public void enable() { public void enable() {
@ -50,7 +59,9 @@ public abstract class AbstractMiningCoordinator<
if (isEnabled) { if (isEnabled) {
return; return;
} }
startAsyncMiningOperation(); if (syncState.isInSync()) {
startAsyncMiningOperation();
}
isEnabled = true; isEnabled = true;
} }
} }
@ -67,7 +78,7 @@ public abstract class AbstractMiningCoordinator<
public boolean isRunning() { public boolean isRunning() {
synchronized (this) { synchronized (this) {
return isEnabled; return currentRunningMiner.isPresent();
} }
} }
@ -78,28 +89,35 @@ public abstract class AbstractMiningCoordinator<
protected void haltCurrentMiningOperation() { protected void haltCurrentMiningOperation() {
currentRunningMiner.ifPresent(M::cancel); currentRunningMiner.ifPresent(M::cancel);
currentRunningMiner = Optional.empty();
} }
@Override @Override
public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) { public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) {
synchronized (this) { synchronized (this) {
if (isEnabled && shouldStartNewMiner(event)) { if (isEnabled && event.isNewCanonicalHead()) {
haltCurrentMiningOperation(); haltCurrentMiningOperation();
startAsyncMiningOperation(); if (syncState.isInSync()) {
startAsyncMiningOperation();
}
} }
} }
} }
private boolean shouldStartNewMiner(final BlockAddedEvent event) { public void inSyncChanged(final boolean inSync) {
return event.getEventType() != EventType.FORK; synchronized (this) {
} if (isEnabled && inSync) {
LOG.info("Resuming mining operations");
public void removeMinedBlockObserver(final long id) { startAsyncMiningOperation();
minedBlockObservers.unsubscribe(id); } else if (!inSync) {
LOG.info("Pausing mining while behind chain head");
haltCurrentMiningOperation();
}
}
} }
public long addMinedBlockObserver(final MinedBlockObserver obs) { public void addMinedBlockObserver(final MinedBlockObserver obs) {
return minedBlockObservers.subscribe(obs); minedBlockObservers.subscribe(obs);
} }
// Required for JSON RPC, and are deemed to be valid for all mining mechanisms // Required for JSON RPC, and are deemed to be valid for all mining mechanisms
@ -117,31 +135,26 @@ public abstract class AbstractMiningCoordinator<
public void setCoinbase(final Address coinbase) { public void setCoinbase(final Address coinbase) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Current consensus mechanism prevents" + " setting coinbase."); "Current consensus mechanism prevents setting coinbase.");
} }
public Optional<Address> getCoinbase() { public Optional<Address> getCoinbase() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Current consensus mechanism prevents" + " querying of coinbase."); "Current consensus mechanism prevents querying of coinbase.");
} }
public Optional<Long> hashesPerSecond() { public Optional<Long> hashesPerSecond() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Current consensus mechanism prevents querying " + "of hashrate."); "Current consensus mechanism prevents querying of hashrate.");
} }
public Optional<EthHashSolverInputs> getWorkDefinition() { public Optional<EthHashSolverInputs> getWorkDefinition() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Current consensus mechanism prevents querying " + "work definition."); "Current consensus mechanism prevents querying work definition.");
} }
public boolean submitWork(final EthHashSolution solution) { public boolean submitWork(final EthHashSolution solution) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Current consensus mechanism prevents submission of work" + " solutions."); "Current consensus mechanism prevents submission of work solutions.");
}
public interface MinedBlockObserver {
void blockMined(Block block);
} }
} }

@ -13,7 +13,7 @@
package tech.pegasys.pantheon.ethereum.blockcreation; package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockImporter; import tech.pegasys.pantheon.ethereum.core.BlockImporter;

@ -10,17 +10,22 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 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. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.ethereum.mainnet; package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockCreator;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderBuilder; import tech.pegasys.pantheon.ethereum.core.BlockHeaderBuilder;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.ethereum.core.SealableBlockHeader; import tech.pegasys.pantheon.ethereum.core.SealableBlockHeader;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.mainnet.EthHash;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolver;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolver.EthHashSolverJob; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolver.EthHashSolverJob;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.util.bytes.BytesValues; import tech.pegasys.pantheon.util.bytes.BytesValues;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;

@ -13,9 +13,8 @@
package tech.pegasys.pantheon.ethereum.blockcreation; package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashBlockCreator;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;

@ -13,11 +13,11 @@
package tech.pegasys.pantheon.ethereum.blockcreation; package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashBlockCreator;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolver; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolver;
import tech.pegasys.pantheon.ethereum.mainnet.EthHasher; import tech.pegasys.pantheon.ethereum.mainnet.EthHasher;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver; import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolverInputs;
@ -31,8 +32,8 @@ public class EthHashMiningCoordinator extends AbstractMiningCoordinator<Void, Et
private volatile Optional<Long> cachedHashesPerSecond = Optional.empty(); private volatile Optional<Long> cachedHashesPerSecond = Optional.empty();
public EthHashMiningCoordinator( public EthHashMiningCoordinator(
final Blockchain blockchain, final EthHashMinerExecutor executor) { final Blockchain blockchain, final EthHashMinerExecutor executor, final SyncState syncState) {
super(blockchain, executor); super(blockchain, executor, syncState);
this.executor = executor; this.executor = executor;
} }
@ -78,5 +79,6 @@ public class EthHashMiningCoordinator extends AbstractMiningCoordinator<Void, Et
miner.cancel(); miner.cancel();
miner.getHashesPerSecond().ifPresent(val -> cachedHashesPerSecond = Optional.of(val)); miner.getHashesPerSecond().ifPresent(val -> cachedHashesPerSecond = Optional.of(val));
}); });
currentRunningMiner = Optional.empty();
} }
} }

@ -0,0 +1,138 @@
/*
* Copyright 2018 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.blockcreation;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent;
import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockBody;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
public class AbstractMiningCoordinatorTest {
private static final Block BLOCK =
new Block(
new BlockHeaderTestFixture().buildHeader(),
new BlockBody(Collections.emptyList(), Collections.emptyList()));
private final Blockchain blockchain = mock(Blockchain.class);
private final EthHashMinerExecutor minerExecutor = mock(EthHashMinerExecutor.class);
private final SyncState syncState = mock(SyncState.class);
private final EthHashBlockMiner blockMiner = mock(EthHashBlockMiner.class);
private final TestMiningCoordinator miningCoordinator =
new TestMiningCoordinator(blockchain, minerExecutor, syncState);
@Before
public void setUp() {
when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner);
}
@Test
public void shouldNotStartMiningWhenEnabledAndOutOfSync() {
when(syncState.isInSync()).thenReturn(false);
miningCoordinator.enable();
verifyZeroInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldStartMiningWhenEnabledAndInSync() {
when(syncState.isInSync()).thenReturn(true);
miningCoordinator.enable();
verify(minerExecutor).startAsyncMining(any(), any());
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldStartMiningWhenEnabledAndBecomeInSync() {
when(syncState.isInSync()).thenReturn(false);
miningCoordinator.enable();
miningCoordinator.inSyncChanged(true);
verify(minerExecutor).startAsyncMining(any(), any());
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldHaltMiningWhenBecomingOutOfSync() {
when(syncState.isInSync()).thenReturn(true);
miningCoordinator.enable();
verify(minerExecutor).startAsyncMining(any(), any());
miningCoordinator.inSyncChanged(false);
verify(blockMiner).cancel();
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldNotStartWhenBlockAddedAndOutOfSync() {
when(syncState.isInSync()).thenReturn(false);
miningCoordinator.enable();
miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldRestartMiningWhenBlockAddedAndInSync() {
when(syncState.isInSync()).thenReturn(true);
miningCoordinator.enable();
miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain);
verify(blockMiner).cancel();
verify(minerExecutor, times(2)).startAsyncMining(any(), any());
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldNotStartMiningWhenBecomingInSyncIfMinerNotEnabled() {
when(syncState.isInSync()).thenReturn(true);
miningCoordinator.inSyncChanged(true);
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
@Test
public void shouldNotStartMiningWhenBlockAddedAndInSyncIfMinerNotEnabled() {
when(syncState.isInSync()).thenReturn(true);
miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner);
}
public static class TestMiningCoordinator
extends AbstractMiningCoordinator<Void, EthHashBlockMiner> {
public TestMiningCoordinator(
final Blockchain blockchain,
final AbstractMinerExecutor<Void, EthHashBlockMiner> executor,
final SyncState syncState) {
super(blockchain, executor, syncState);
}
}
}

@ -20,12 +20,11 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockBody; import tech.pegasys.pantheon.ethereum.core.BlockBody;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.BlockImporter; import tech.pegasys.pantheon.ethereum.core.BlockImporter;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashBlockCreator;
import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode; import tech.pegasys.pantheon.ethereum.mainnet.HeaderValidationMode;
import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;

@ -10,13 +10,16 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 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. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.ethereum.mainnet; package tech.pegasys.pantheon.ethereum.blockcreation;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.ExecutionContextTestFixture; import tech.pegasys.pantheon.ethereum.core.ExecutionContextTestFixture;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolver;
import tech.pegasys.pantheon.ethereum.mainnet.EthHasher.Light;
import tech.pegasys.pantheon.ethereum.mainnet.ValidationTestUtils;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.io.IOException; import java.io.IOException;
@ -42,8 +45,7 @@ public class EthHashBlockCreatorTest {
@Test @Test
public void createMainnetBlock1() throws IOException { public void createMainnetBlock1() throws IOException {
final EthHashSolver solver = final EthHashSolver solver = new EthHashSolver(Lists.newArrayList(BLOCK_1_NONCE), new Light());
new EthHashSolver(Lists.newArrayList(BLOCK_1_NONCE), new EthHasher.Light());
final EthHashBlockCreator blockCreator = final EthHashBlockCreator blockCreator =
new EthHashBlockCreator( new EthHashBlockCreator(
BLOCK_1_COINBASE, BLOCK_1_COINBASE,

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.ethereum.blockcreation;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.PendingTransactions;
import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.Subscribers;

@ -19,22 +19,31 @@ import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.core.ExecutionContextTestFixture; import tech.pegasys.pantheon.ethereum.core.ExecutionContextTestFixture;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution; import tech.pegasys.pantheon.ethereum.mainnet.EthHashSolution;
import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.Bytes32;
import java.util.Optional; import java.util.Optional;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class EthHashMiningCoordinatorTest { public class EthHashMiningCoordinatorTest {
private final ExecutionContextTestFixture executionContext = new ExecutionContextTestFixture(); private final ExecutionContextTestFixture executionContext = new ExecutionContextTestFixture();
private final SyncState syncState = mock(SyncState.class);
private final EthHashMinerExecutor executor = mock(EthHashMinerExecutor.class);
private final EthHashBlockMiner miner = mock(EthHashBlockMiner.class);
@Before
public void setUp() {
when(syncState.isInSync()).thenReturn(true);
}
@Test @Test
public void miningCoordinatorIsCreatedDisabledWithNoReportableMiningStatistics() { public void miningCoordinatorIsCreatedDisabledWithNoReportableMiningStatistics() {
final EthHashMinerExecutor executor = mock(EthHashMinerExecutor.class);
final EthHashMiningCoordinator miningCoordinator = final EthHashMiningCoordinator miningCoordinator =
new EthHashMiningCoordinator(executionContext.getBlockchain(), executor); new EthHashMiningCoordinator(executionContext.getBlockchain(), executor, syncState);
final EthHashSolution solution = new EthHashSolution(1L, Hash.EMPTY, new byte[Bytes32.SIZE]); final EthHashSolution solution = new EthHashSolution(1L, Hash.EMPTY, new byte[Bytes32.SIZE]);
assertThat(miningCoordinator.isRunning()).isFalse(); assertThat(miningCoordinator.isRunning()).isFalse();
@ -45,21 +54,17 @@ public class EthHashMiningCoordinatorTest {
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void reportedHashRateIsCachedIfNoCurrentDataInMiner() throws InterruptedException { public void reportedHashRateIsCachedIfNoCurrentDataInMiner() {
final EthHashBlockMiner miner = mock(EthHashBlockMiner.class);
final Optional<Long> hashRate1 = Optional.of(10L); final Optional<Long> hashRate1 = Optional.of(10L);
final Optional<Long> hashRate2 = Optional.empty(); final Optional<Long> hashRate2 = Optional.empty();
final Optional<Long> hashRate3 = Optional.of(20L); final Optional<Long> hashRate3 = Optional.of(20L);
when(miner.getHashesPerSecond()).thenReturn(hashRate1, hashRate2, hashRate3); when(miner.getHashesPerSecond()).thenReturn(hashRate1, hashRate2, hashRate3);
final EthHashMinerExecutor executor = mock(EthHashMinerExecutor.class);
when(executor.startAsyncMining(any(), any())).thenReturn(miner); when(executor.startAsyncMining(any(), any())).thenReturn(miner);
final EthHashMiningCoordinator miningCoordinator = final EthHashMiningCoordinator miningCoordinator =
new EthHashMiningCoordinator(executionContext.getBlockchain(), executor); new EthHashMiningCoordinator(executionContext.getBlockchain(), executor, syncState);
miningCoordinator.enable(); // Must enable prior returning data miningCoordinator.enable(); // Must enable prior returning data
assertThat(miningCoordinator.hashesPerSecond()).isEqualTo(hashRate1); assertThat(miningCoordinator.hashesPerSecond()).isEqualTo(hashRate1);

@ -64,6 +64,10 @@ public class BlockAddedEvent {
return block; return block;
} }
public boolean isNewCanonicalHead() {
return eventType != EventType.FORK;
}
public EventType getEventType() { public EventType getEventType() {
return eventType; return eventType;
} }

@ -0,0 +1,19 @@
/*
* Copyright 2018 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.chain;
import tech.pegasys.pantheon.ethereum.core.Block;
public interface MinedBlockObserver {
void blockMined(Block block);
}

@ -10,10 +10,8 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 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. * specific language governing permissions and limitations under the License.
*/ */
package tech.pegasys.pantheon.ethereum.blockcreation; package tech.pegasys.pantheon.ethereum.core;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
import java.util.Optional; import java.util.Optional;

@ -12,7 +12,6 @@
*/ */
package tech.pegasys.pantheon.ethereum.core; package tech.pegasys.pantheon.ethereum.core;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.util.bytes.BytesValue; import tech.pegasys.pantheon.util.bytes.BytesValue;
public class MiningParametersTestBuilder { public class MiningParametersTestBuilder {

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.ethereum.eth.manager;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.util.Subscribers;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
@ -25,6 +26,16 @@ public class ChainState {
private volatile long estimatedHeight = 0L; private volatile long estimatedHeight = 0L;
private volatile boolean estimatedHeightKnown = false; private volatile boolean estimatedHeightKnown = false;
private final Subscribers<EstimatedHeightListener> estimatedHeightListeners = new Subscribers<>();
public long addEstimatedHeightListener(final EstimatedHeightListener listener) {
return estimatedHeightListeners.subscribe(listener);
}
public void removeEstimatedHeightListener(final long listenerId) {
estimatedHeightListeners.unsubscribe(listenerId);
}
public boolean hasEstimatedHeight() { public boolean hasEstimatedHeight() {
return estimatedHeightKnown; return estimatedHeightKnown;
} }
@ -55,7 +66,7 @@ public class ChainState {
public void update(final BlockHeader header) { public void update(final BlockHeader header) {
synchronized (this) { synchronized (this) {
if (bestBlock.hash.equals(header.getHash())) { if (header.getHash().equals(bestBlock.hash)) {
bestBlock.number = header.getNumber(); bestBlock.number = header.getNumber();
} }
updateHeightEstimate(header.getNumber()); updateHeightEstimate(header.getNumber());
@ -77,6 +88,7 @@ public class ChainState {
estimatedHeightKnown = true; estimatedHeightKnown = true;
if (blockNumber > estimatedHeight) { if (blockNumber > estimatedHeight) {
estimatedHeight = blockNumber; estimatedHeight = blockNumber;
estimatedHeightListeners.forEach(e -> e.onEstimatedHeightChanged(estimatedHeight));
} }
} }
@ -115,4 +127,9 @@ public class ChainState {
.toString(); .toString();
} }
} }
@FunctionalInterface
public interface EstimatedHeightListener {
void onEstimatedHeightChanged(long estimatedHeight);
}
} }

@ -15,6 +15,7 @@ package tech.pegasys.pantheon.ethereum.eth.manager;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.eth.manager.ChainState.EstimatedHeightListener;
import tech.pegasys.pantheon.ethereum.eth.manager.RequestManager.ResponseStream; import tech.pegasys.pantheon.ethereum.eth.manager.RequestManager.ResponseStream;
import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62; import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62;
import tech.pegasys.pantheon.ethereum.eth.messages.EthPV63; import tech.pegasys.pantheon.ethereum.eth.messages.EthPV63;
@ -81,6 +82,14 @@ public class EthPeer {
this.onStatusesExchanged.set(onStatusesExchanged); this.onStatusesExchanged.set(onStatusesExchanged);
} }
public long addChainEstimatedHeightListener(final EstimatedHeightListener listener) {
return chainHeadState.addEstimatedHeightListener(listener);
}
public void removeChainEstimatedHeightListener(final long listenerId) {
chainHeadState.removeEstimatedHeightListener(listenerId);
}
public void recordRequestTimeout(final int requestCode) { public void recordRequestTimeout(final int requestCode) {
LOG.debug("Timed out while waiting for response from peer {}", this); LOG.debug("Timed out while waiting for response from peer {}", this);
reputation.recordRequestTimeout(requestCode).ifPresent(this::disconnect); reputation.recordRequestTimeout(requestCode).ifPresent(this::disconnect);

@ -14,8 +14,8 @@ package tech.pegasys.pantheon.ethereum.eth.manager;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.eth.EthProtocol; import tech.pegasys.pantheon.ethereum.eth.EthProtocol;

@ -70,14 +70,15 @@ public class BlockPropagationManager<C> {
final ProtocolSchedule<C> protocolSchedule, final ProtocolSchedule<C> protocolSchedule,
final ProtocolContext<C> protocolContext, final ProtocolContext<C> protocolContext,
final EthContext ethContext, final EthContext ethContext,
final SyncState syncState) { final SyncState syncState,
final PendingBlocks pendingBlocks) {
this.config = config; this.config = config;
this.protocolSchedule = protocolSchedule; this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext; this.protocolContext = protocolContext;
this.ethContext = ethContext; this.ethContext = ethContext;
this.syncState = syncState; this.syncState = syncState;
pendingBlocks = syncState.pendingBlocks(); this.pendingBlocks = pendingBlocks;
} }
public void start() { public void start() {

@ -39,12 +39,17 @@ public class DefaultSynchronizer<C> implements Synchronizer {
final SynchronizerConfiguration syncConfig, final SynchronizerConfiguration syncConfig,
final ProtocolSchedule<C> protocolSchedule, final ProtocolSchedule<C> protocolSchedule,
final ProtocolContext<C> protocolContext, final ProtocolContext<C> protocolContext,
final EthContext ethContext) { final EthContext ethContext,
this.syncState = final SyncState syncState) {
new SyncState(protocolContext.getBlockchain(), ethContext, new PendingBlocks()); this.syncState = syncState;
this.blockPropagationManager = this.blockPropagationManager =
new BlockPropagationManager<>( new BlockPropagationManager<>(
syncConfig, protocolSchedule, protocolContext, ethContext, syncState); syncConfig,
protocolSchedule,
protocolContext,
ethContext,
syncState,
new PendingBlocks());
this.downloader = this.downloader =
new Downloader<>(syncConfig, protocolSchedule, protocolContext, ethContext, syncState); new Downloader<>(syncConfig, protocolSchedule, protocolContext, ethContext, syncState);

@ -327,7 +327,7 @@ public class Downloader<C> {
return CompletableFuture.completedFuture(Collections.emptyList()); return CompletableFuture.completedFuture(Collections.emptyList());
} }
CompletableFuture<List<Block>> importedBlocks; final CompletableFuture<List<Block>> importedBlocks;
if (checkpointHeaders.size() < 2) { if (checkpointHeaders.size() < 2) {
// Download blocks without constraining the end block // Download blocks without constraining the end block
final ImportBlocksTask<C> importTask = final ImportBlocksTask<C> importTask =
@ -382,9 +382,7 @@ public class Downloader<C> {
chainSegmentTimeouts = 0; chainSegmentTimeouts = 0;
final BlockHeader lastImportedCheckpoint = checkpointHeaders.getLast(); final BlockHeader lastImportedCheckpoint = checkpointHeaders.getLast();
checkpointHeaders.clear(); checkpointHeaders.clear();
syncState syncState.setCommonAncestor(lastImportedCheckpoint);
.syncTarget()
.ifPresent(target -> target.setCommonAncestor(lastImportedCheckpoint));
} }
}); });
} }
@ -400,9 +398,7 @@ public class Downloader<C> {
final BlockHeader lastImportedCheckpointHeader = imported.get(imported.size() - 1); final BlockHeader lastImportedCheckpointHeader = imported.get(imported.size() - 1);
// The first checkpoint header is always present in the blockchain. // The first checkpoint header is always present in the blockchain.
checkpointHeaders.addFirst(lastImportedCheckpointHeader); checkpointHeaders.addFirst(lastImportedCheckpointHeader);
syncState syncState.setCommonAncestor(lastImportedCheckpointHeader);
.syncTarget()
.ifPresent(target -> target.setCommonAncestor(lastImportedCheckpointHeader));
return imported.size() > 1; return imported.size() > 1;
} }
} }

@ -15,7 +15,6 @@ package tech.pegasys.pantheon.ethereum.eth.sync;
import static org.apache.logging.log4j.LogManager.getLogger; import static org.apache.logging.log4j.LogManager.getLogger;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent; import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent.EventType;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver; import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer;
@ -74,7 +73,7 @@ public class TrailingPeerLimiter implements BlockAddedObserver {
@Override @Override
public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) { public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) {
if (event.getEventType() != EventType.FORK if (event.isNewCanonicalHead()
&& event.getBlock().getHeader().getNumber() % RECHECK_PEERS_WHEN_BLOCK_NUMBER_MULTIPLE_OF && event.getBlock().getHeader().getNumber() % RECHECK_PEERS_WHEN_BLOCK_NUMBER_MULTIPLE_OF
== 0) { == 0) {
enforceTrailingPeerLimit(); enforceTrailingPeerLimit();

@ -15,26 +15,38 @@ package tech.pegasys.pantheon.ethereum.eth.sync.state;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.SyncStatus; import tech.pegasys.pantheon.ethereum.core.SyncStatus;
import tech.pegasys.pantheon.ethereum.eth.manager.EthContext;
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer;
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeers;
import tech.pegasys.pantheon.util.Subscribers;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;
import java.util.Optional; import java.util.Optional;
public class SyncState { public class SyncState {
private static final long SYNC_TOLERANCE = 5;
private final Blockchain blockchain; private final Blockchain blockchain;
private final EthContext ethContext; private final EthPeers ethPeers;
private final long startingBlock; private final long startingBlock;
private final PendingBlocks pendingBlocks; private boolean lastInSync = true;
private final Subscribers<InSyncListener> inSyncListeners = new Subscribers<>();
private Optional<SyncTarget> syncTarget = Optional.empty(); private Optional<SyncTarget> syncTarget = Optional.empty();
private long chainHeightListenerId;
public SyncState( public SyncState(final Blockchain blockchain, final EthPeers ethPeers) {
final Blockchain blockchain, final EthContext ethContext, final PendingBlocks pendingBlocks) {
this.blockchain = blockchain; this.blockchain = blockchain;
this.ethContext = ethContext; this.ethPeers = ethPeers;
this.startingBlock = chainHeadNumber(); this.startingBlock = chainHeadNumber();
this.pendingBlocks = pendingBlocks; blockchain.observeBlockAdded(
(event, chain) -> {
if (event.isNewCanonicalHead()) {
checkInSync();
}
});
}
public void addInSyncListener(final InSyncListener observer) {
inSyncListeners.subscribe(observer);
} }
public SyncStatus syncStatus() { public SyncStatus syncStatus() {
@ -53,22 +65,45 @@ public class SyncState {
return blockchain.getChainHead().getTotalDifficulty(); return blockchain.getChainHead().getTotalDifficulty();
} }
public PendingBlocks pendingBlocks() {
return pendingBlocks;
}
public Optional<SyncTarget> syncTarget() { public Optional<SyncTarget> syncTarget() {
return syncTarget; return syncTarget;
} }
public SyncTarget setSyncTarget(final EthPeer peer, final BlockHeader commonAncestor) { public SyncTarget setSyncTarget(final EthPeer peer, final BlockHeader commonAncestor) {
final SyncTarget target = new SyncTarget(peer, commonAncestor); final SyncTarget syncTarget = new SyncTarget(peer, commonAncestor);
this.syncTarget = Optional.of(target); replaceSyncTarget(Optional.of(syncTarget));
return target; return syncTarget;
}
public boolean isInSync() {
return syncTarget
.map(
t -> t.estimatedTargetHeight() - blockchain.getChainHeadBlockNumber() <= SYNC_TOLERANCE)
.orElse(true);
}
public void setCommonAncestor(final BlockHeader commonAncestor) {
syncTarget.ifPresent(target -> target.setCommonAncestor(commonAncestor));
} }
public void clearSyncTarget() { public void clearSyncTarget() {
this.syncTarget = Optional.empty(); replaceSyncTarget(Optional.empty());
}
private void replaceSyncTarget(final Optional<SyncTarget> newTarget) {
syncTarget.ifPresent(this::removeEstimatedHeightListener);
syncTarget = newTarget;
newTarget.ifPresent(this::addEstimatedHeightListener);
checkInSync();
}
private void removeEstimatedHeightListener(final SyncTarget target) {
target.removePeerChainEstimatedHeightListener(chainHeightListenerId);
}
private void addEstimatedHeightListener(final SyncTarget target) {
chainHeightListenerId =
target.addPeerChainEstimatedHeightListener(estimatedHeight -> checkInSync());
} }
public long bestChainHeight() { public long bestChainHeight() {
@ -79,10 +114,19 @@ public class SyncState {
public long bestChainHeight(final long localChainHeight) { public long bestChainHeight(final long localChainHeight) {
return Math.max( return Math.max(
localChainHeight, localChainHeight,
ethContext ethPeers.bestPeer().map(p -> p.chainState().getEstimatedHeight()).orElse(localChainHeight));
.getEthPeers() }
.bestPeer()
.map(p -> p.chainState().getEstimatedHeight()) private synchronized void checkInSync() {
.orElse(localChainHeight)); final boolean currentSyncStatus = isInSync();
if (lastInSync != currentSyncStatus) {
lastInSync = currentSyncStatus;
inSyncListeners.forEach(c -> c.onSyncStatusChanged(currentSyncStatus));
}
}
@FunctionalInterface
public interface InSyncListener {
void onSyncStatusChanged(boolean newSyncStatus);
} }
} }

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.ethereum.eth.sync.state;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.eth.manager.ChainState; import tech.pegasys.pantheon.ethereum.eth.manager.ChainState;
import tech.pegasys.pantheon.ethereum.eth.manager.ChainState.EstimatedHeightListener;
import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
@ -23,7 +24,7 @@ public class SyncTarget {
private final EthPeer peer; private final EthPeer peer;
private BlockHeader commonAncestor; private BlockHeader commonAncestor;
public SyncTarget(final EthPeer peer, final BlockHeader commonAncestor) { SyncTarget(final EthPeer peer, final BlockHeader commonAncestor) {
this.peer = peer; this.peer = peer;
this.commonAncestor = commonAncestor; this.commonAncestor = commonAncestor;
} }
@ -36,10 +37,22 @@ public class SyncTarget {
return commonAncestor; return commonAncestor;
} }
public void setCommonAncestor(final BlockHeader commonAncestor) { void setCommonAncestor(final BlockHeader commonAncestor) {
this.commonAncestor = commonAncestor; this.commonAncestor = commonAncestor;
} }
public long addPeerChainEstimatedHeightListener(final EstimatedHeightListener listener) {
return peer.addChainEstimatedHeightListener(listener);
}
public void removePeerChainEstimatedHeightListener(final long listenerId) {
peer.removeChainEstimatedHeightListener(listenerId);
}
public long estimatedTargetHeight() {
return peer.chainState().getEstimatedHeight();
}
@Override @Override
public String toString() { public String toString() {
final ChainState chainState = peer.chainState(); final ChainState chainState = peer.chainState();

@ -13,10 +13,14 @@
package tech.pegasys.pantheon.ethereum.eth.manager; package tech.pegasys.pantheon.ethereum.eth.manager;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture; import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.eth.manager.ChainState.EstimatedHeightListener;
import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator;
import tech.pegasys.pantheon.util.uint.UInt256; import tech.pegasys.pantheon.util.uint.UInt256;
@ -228,4 +232,59 @@ public class ChainStateTest {
assertThat(chainState.hasEstimatedHeight()).isTrue(); assertThat(chainState.hasEstimatedHeight()).isTrue();
} }
@Test
public void observersInformedWhenHeightUpdatedViaHashAndNumber() {
final long blockNumber = 12;
final BlockHeader bestBlockHeader =
new BlockHeaderTestFixture().number(blockNumber).buildHeader();
chainState.statusReceived(bestBlockHeader.getHash(), INITIAL_TOTAL_DIFFICULTY);
final EstimatedHeightListener listener = mock(EstimatedHeightListener.class);
chainState.addEstimatedHeightListener(listener);
chainState.update(bestBlockHeader.getHash(), blockNumber);
verify(listener).onEstimatedHeightChanged(blockNumber);
}
@Test
public void observersInformedWhenHeightUpdatedViaHeader() {
final long blockNumber = 12;
final BlockHeader bestBlockHeader =
new BlockHeaderTestFixture().number(blockNumber).buildHeader();
chainState.statusReceived(bestBlockHeader.getHash(), INITIAL_TOTAL_DIFFICULTY);
final EstimatedHeightListener listener = mock(EstimatedHeightListener.class);
chainState.addEstimatedHeightListener(listener);
chainState.update(bestBlockHeader);
verify(listener).onEstimatedHeightChanged(blockNumber);
}
@Test
public void observersInformedWhenHeightUpdatedViaHeaderAndTD() {
final long blockNumber = 12;
final BlockHeader bestBlockHeader =
new BlockHeaderTestFixture().number(blockNumber).buildHeader();
chainState.statusReceived(bestBlockHeader.getHash(), INITIAL_TOTAL_DIFFICULTY);
final EstimatedHeightListener listener = mock(EstimatedHeightListener.class);
chainState.addEstimatedHeightListener(listener);
chainState.update(bestBlockHeader, INITIAL_TOTAL_DIFFICULTY);
verify(listener).onEstimatedHeightChanged(blockNumber);
}
@Test
public void observersNotInformedWhenHeightLowers() {
final long blockNumber = 12;
final BlockHeader bestBlockHeader =
new BlockHeaderTestFixture().number(blockNumber).buildHeader();
chainState.statusReceived(bestBlockHeader.getHash(), INITIAL_TOTAL_DIFFICULTY);
final EstimatedHeightListener listener = mock(EstimatedHeightListener.class);
chainState.addEstimatedHeightListener(listener);
chainState.update(bestBlockHeader);
verify(listener).onEstimatedHeightChanged(blockNumber);
final long lowerBlockNumber = 12;
final BlockHeader lowerBlockHeader =
new BlockHeaderTestFixture().number(lowerBlockNumber).buildHeader();
chainState.update(lowerBlockHeader);
verifyNoMoreInteractions(listener);
}
} }

@ -54,6 +54,7 @@ public class BlockPropagationManagerTest {
private EthProtocolManager ethProtocolManager; private EthProtocolManager ethProtocolManager;
private BlockPropagationManager<Void> blockPropagationManager; private BlockPropagationManager<Void> blockPropagationManager;
private SynchronizerConfiguration syncConfig; private SynchronizerConfiguration syncConfig;
private final PendingBlocks pendingBlocks = new PendingBlocks();
private SyncState syncState; private SyncState syncState;
@BeforeClass @BeforeClass
@ -78,14 +79,15 @@ public class BlockPropagationManagerTest {
.blockPropagationRange(-3, 5) .blockPropagationRange(-3, 5)
.build() .build()
.validated(blockchain); .validated(blockchain);
syncState = new SyncState(blockchain, ethProtocolManager.ethContext(), new PendingBlocks()); syncState = new SyncState(blockchain, ethProtocolManager.ethContext().getEthPeers());
blockPropagationManager = blockPropagationManager =
new BlockPropagationManager<>( new BlockPropagationManager<>(
syncConfig, syncConfig,
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethProtocolManager.ethContext(), ethProtocolManager.ethContext(),
syncState); syncState,
pendingBlocks);
} }
@Test @Test
@ -459,7 +461,8 @@ public class BlockPropagationManagerTest {
protocolSchedule, protocolSchedule,
protocolContext, protocolContext,
ethProtocolManager.ethContext(), ethProtocolManager.ethContext(),
syncState); syncState,
pendingBlocks);
final BlockDataGenerator gen = new BlockDataGenerator(); final BlockDataGenerator gen = new BlockDataGenerator();
// Import some blocks // Import some blocks
@ -479,20 +482,20 @@ public class BlockPropagationManagerTest {
// Check that we pushed our block into the pending collection // Check that we pushed our block into the pending collection
assertThat(blockchain.contains(blockToPurge.getHash())).isFalse(); assertThat(blockchain.contains(blockToPurge.getHash())).isFalse();
assertThat(syncState.pendingBlocks().contains(blockToPurge.getHash())).isTrue(); assertThat(pendingBlocks.contains(blockToPurge.getHash())).isTrue();
// Import blocks until we bury the target block far enough to be cleaned up // Import blocks until we bury the target block far enough to be cleaned up
for (int i = 0; i < oldBlocksToImport; i++) { for (int i = 0; i < oldBlocksToImport; i++) {
blockchainUtil.importBlockAtIndex((int) blockchain.getChainHeadBlockNumber() + 1); blockchainUtil.importBlockAtIndex((int) blockchain.getChainHeadBlockNumber() + 1);
assertThat(blockchain.contains(blockToPurge.getHash())).isFalse(); assertThat(blockchain.contains(blockToPurge.getHash())).isFalse();
assertThat(syncState.pendingBlocks().contains(blockToPurge.getHash())).isTrue(); assertThat(pendingBlocks.contains(blockToPurge.getHash())).isTrue();
} }
// Import again to trigger cleanup // Import again to trigger cleanup
blockchainUtil.importBlockAtIndex((int) blockchain.getChainHeadBlockNumber() + 1); blockchainUtil.importBlockAtIndex((int) blockchain.getChainHeadBlockNumber() + 1);
assertThat(blockchain.contains(blockToPurge.getHash())).isFalse(); assertThat(blockchain.contains(blockToPurge.getHash())).isFalse();
assertThat(syncState.pendingBlocks().contains(blockToPurge.getHash())).isFalse(); assertThat(pendingBlocks.contains(blockToPurge.getHash())).isFalse();
} }
@Test @Test

@ -35,7 +35,6 @@ import tech.pegasys.pantheon.ethereum.eth.manager.RespondingEthPeer.Responder;
import tech.pegasys.pantheon.ethereum.eth.manager.ethtaskutils.BlockchainSetupUtil; import tech.pegasys.pantheon.ethereum.eth.manager.ethtaskutils.BlockchainSetupUtil;
import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62; import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62;
import tech.pegasys.pantheon.ethereum.eth.messages.GetBlockHeadersMessage; import tech.pegasys.pantheon.ethereum.eth.messages.GetBlockHeadersMessage;
import tech.pegasys.pantheon.ethereum.eth.sync.state.PendingBlocks;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState; import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction; import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction;
@ -81,7 +80,7 @@ public class DownloaderTest {
protocolContext = localBlockchainSetup.getProtocolContext(); protocolContext = localBlockchainSetup.getProtocolContext();
ethProtocolManager = EthProtocolManagerTestUtil.create(localBlockchain); ethProtocolManager = EthProtocolManagerTestUtil.create(localBlockchain);
ethContext = ethProtocolManager.ethContext(); ethContext = ethProtocolManager.ethContext();
syncState = new SyncState(protocolContext.getBlockchain(), ethContext, new PendingBlocks()); syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers());
} }
private Downloader<?> downloader(final SynchronizerConfiguration syncConfig) { private Downloader<?> downloader(final SynchronizerConfiguration syncConfig) {

@ -0,0 +1,114 @@
/*
* Copyright 2018 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.state;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedEvent;
import tech.pegasys.pantheon.ethereum.chain.BlockAddedObserver;
import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockBody;
import tech.pegasys.pantheon.ethereum.core.BlockHeader;
import tech.pegasys.pantheon.ethereum.core.BlockHeaderTestFixture;
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 java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
public class SyncStateTest {
private static final long OUR_CHAIN_HEAD_NUMBER = 500;
private static final long TARGET_SYNC_NUMBER = OUR_CHAIN_HEAD_NUMBER + 100;
private final Blockchain blockchain = mock(Blockchain.class);
private final EthPeers ethPeers = mock(EthPeers.class);
private final SyncState.InSyncListener inSyncListener = mock(SyncState.InSyncListener.class);
private final EthPeer peer = mock(EthPeer.class);
private final ChainState peerChainHead = new ChainState();
private SyncState syncState;
private BlockAddedObserver blockAddedObserver;
@Before
public void setUp() {
final ArgumentCaptor<BlockAddedObserver> captor =
ArgumentCaptor.forClass(BlockAddedObserver.class);
when(blockchain.observeBlockAdded(captor.capture())).thenReturn(1L);
when(peer.chainState()).thenReturn(peerChainHead);
when(blockchain.getChainHeadBlockNumber()).thenReturn(OUR_CHAIN_HEAD_NUMBER);
syncState = new SyncState(blockchain, ethPeers);
blockAddedObserver = captor.getValue();
syncState.addInSyncListener(inSyncListener);
}
@Test
public void shouldBeInSyncWhenNoSyncTargetHasBeenSet() {
assertThat(syncState.isInSync()).isTrue();
}
@Test
public void shouldSwitchToNotInSyncWhenSyncTargetWithBetterChainSet() {
final BlockHeader bestBlockHeader = targetBlockHeader();
peerChainHead.update(bestBlockHeader);
syncState.setSyncTarget(peer, bestBlockHeader);
assertThat(syncState.isInSync()).isFalse();
verify(inSyncListener).onSyncStatusChanged(false);
verifyNoMoreInteractions(inSyncListener);
}
@Test
public void shouldSwitchToInSyncWhenSyncTargetCleared() {
setupOutOfSyncState();
syncState.clearSyncTarget();
verify(inSyncListener).onSyncStatusChanged(true);
verifyNoMoreInteractions(inSyncListener);
}
@Test
public void shouldBecomeInSyncWhenOurBlockchainCatchesUp() {
setupOutOfSyncState();
when(blockchain.getChainHeadBlockNumber()).thenReturn(TARGET_SYNC_NUMBER);
blockAddedObserver.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(
new Block(
targetBlockHeader(),
new BlockBody(Collections.emptyList(), Collections.emptyList()))),
blockchain);
assertThat(syncState.isInSync()).isTrue();
verify(inSyncListener).onSyncStatusChanged(true);
}
private void setupOutOfSyncState() {
final BlockHeader bestBlockHeader = targetBlockHeader();
peerChainHead.update(bestBlockHeader);
syncState.setSyncTarget(peer, bestBlockHeader);
assertThat(syncState.isInSync()).isFalse();
verify(inSyncListener).onSyncStatusChanged(false);
}
private BlockHeader targetBlockHeader() {
return new BlockHeaderTestFixture().number(TARGET_SYNC_NUMBER).buildHeader();
}
}

@ -24,6 +24,7 @@ jar {
dependencies { dependencies {
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation')
implementation project(':ethereum:eth') implementation project(':ethereum:eth')
implementation project(':ethereum:p2p') implementation project(':ethereum:p2p')
implementation project(':ethereum:rlp') implementation project(':ethereum:rlp')

@ -30,6 +30,7 @@ dependencies {
implementation project(':consensus:clique') implementation project(':consensus:clique')
implementation project(':ethereum:eth') implementation project(':ethereum:eth')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation')
implementation project(':ethereum:rlp') implementation project(':ethereum:rlp')
implementation project(':ethereum:p2p') implementation project(':ethereum:p2p')
implementation project(':ethereum:jsonrpc') implementation project(':ethereum:jsonrpc')

@ -20,8 +20,8 @@ import tech.pegasys.pantheon.cli.custom.CorsAllowedOriginsProperty;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis; import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis;
import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis; import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis;
import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;

@ -18,8 +18,8 @@ import static tech.pegasys.pantheon.controller.KeyPairUtil.loadKeyPair;
import tech.pegasys.pantheon.controller.MainnetPantheonController; import tech.pegasys.pantheon.controller.MainnetPantheonController;
import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import java.io.IOException; import java.io.IOException;
@ -46,7 +46,6 @@ public class PantheonControllerBuilder {
GenesisConfig.development(), GenesisConfig.development(),
synchronizerConfiguration, synchronizerConfiguration,
miningParameters, miningParameters,
ethNetworkConfig.getNetworkId(),
nodeKeys); nodeKeys);
} else { } else {
final String genesisConfig = final String genesisConfig =

@ -26,11 +26,11 @@ import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.BlockHashFunction; import tech.pegasys.pantheon.ethereum.core.BlockHashFunction;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer; import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool; import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Util;
@ -41,6 +41,7 @@ import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager;
import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer; import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer;
import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolFactory; import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolFactory;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction; import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction;
@ -140,16 +141,23 @@ public class CliquePantheonController
genesisConfig.getChainId(), genesisConfig.getChainId(),
fastSyncEnabled, fastSyncEnabled,
networkId); networkId);
final SyncState syncState =
new SyncState(
protocolContext.getBlockchain(), ethProtocolManager.ethContext().getEthPeers());
final Synchronizer synchronizer = final Synchronizer synchronizer =
new DefaultSynchronizer<>( new DefaultSynchronizer<>(
syncConfig, protocolSchedule, protocolContext, ethProtocolManager.ethContext()); syncConfig,
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
syncState);
final TransactionPool transactionPool = final TransactionPool transactionPool =
TransactionPoolFactory.createTransactionPool( TransactionPoolFactory.createTransactionPool(
protocolSchedule, protocolContext, ethProtocolManager.ethContext()); protocolSchedule, protocolContext, ethProtocolManager.ethContext());
final ExecutorService minerThreadPool = Executors.newCachedThreadPool(); final ExecutorService minerThreadPool = Executors.newCachedThreadPool();
CliqueMinerExecutor miningExecutor = final CliqueMinerExecutor miningExecutor =
new CliqueMinerExecutor( new CliqueMinerExecutor(
protocolContext, protocolContext,
minerThreadPool, minerThreadPool,
@ -163,8 +171,8 @@ public class CliquePantheonController
Util.publicKeyToAddress(nodeKeys.getPublicKey()), Util.publicKeyToAddress(nodeKeys.getPublicKey()),
secondsBetweenBlocks), secondsBetweenBlocks),
epochManger); epochManger);
CliqueMiningCoordinator miningCoordinator = final CliqueMiningCoordinator miningCoordinator =
new CliqueMiningCoordinator(blockchain, miningExecutor); new CliqueMiningCoordinator(blockchain, miningExecutor, syncState);
miningCoordinator.addMinedBlockObserver(ethProtocolManager); miningCoordinator.addMinedBlockObserver(ethProtocolManager);
// Clique mining is implicitly enabled. // Clique mining is implicitly enabled.

@ -46,6 +46,7 @@ import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager;
import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer; import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer;
import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolFactory; import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolFactory;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction; import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction;
@ -140,8 +141,8 @@ public class IbftPantheonController implements PantheonController<IbftContext, I
final SynchronizerConfiguration syncConfig = taintedSyncConfig.validated(blockchain); final SynchronizerConfiguration syncConfig = taintedSyncConfig.validated(blockchain);
final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST); final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST);
EthProtocolManager ethProtocolManager; final EthProtocolManager ethProtocolManager;
SubProtocol ethSubProtocol; final SubProtocol ethSubProtocol;
if (ottomanTestnetOperation) { if (ottomanTestnetOperation) {
LOG.info("Operating on Ottoman testnet."); LOG.info("Operating on Ottoman testnet.");
ethSubProtocol = Istanbul64Protocol.get(); ethSubProtocol = Istanbul64Protocol.get();
@ -153,9 +154,16 @@ public class IbftPantheonController implements PantheonController<IbftContext, I
ethProtocolManager = ethProtocolManager =
new EthProtocolManager(protocolContext.getBlockchain(), networkId, fastSyncEnabled, 1); new EthProtocolManager(protocolContext.getBlockchain(), networkId, fastSyncEnabled, 1);
} }
final SyncState syncState =
new SyncState(
protocolContext.getBlockchain(), ethProtocolManager.ethContext().getEthPeers());
final Synchronizer synchronizer = final Synchronizer synchronizer =
new DefaultSynchronizer<>( new DefaultSynchronizer<>(
syncConfig, protocolSchedule, protocolContext, ethProtocolManager.ethContext()); syncConfig,
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
syncState);
final IbftEventQueue ibftEventQueue = new IbftEventQueue(); final IbftEventQueue ibftEventQueue = new IbftEventQueue();

@ -20,11 +20,11 @@ import tech.pegasys.pantheon.ethereum.blockcreation.DefaultBlockScheduler;
import tech.pegasys.pantheon.ethereum.blockcreation.EthHashBlockMiner; import tech.pegasys.pantheon.ethereum.blockcreation.EthHashBlockMiner;
import tech.pegasys.pantheon.ethereum.blockcreation.EthHashMinerExecutor; import tech.pegasys.pantheon.ethereum.blockcreation.EthHashMinerExecutor;
import tech.pegasys.pantheon.ethereum.blockcreation.EthHashMiningCoordinator; import tech.pegasys.pantheon.ethereum.blockcreation.EthHashMiningCoordinator;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.core.BlockHashFunction; import tech.pegasys.pantheon.ethereum.core.BlockHashFunction;
import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer; import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool; import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.db.DefaultMutableBlockchain; import tech.pegasys.pantheon.ethereum.db.DefaultMutableBlockchain;
@ -34,6 +34,7 @@ import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager;
import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer; import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer;
import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.eth.sync.state.SyncState;
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolFactory; import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolFactory;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderValidator; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderValidator;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
@ -97,7 +98,6 @@ public class MainnetPantheonController implements PantheonController<Void, EthHa
GenesisConfig.mainnet(), GenesisConfig.mainnet(),
SynchronizerConfiguration.builder().build(), SynchronizerConfiguration.builder().build(),
miningParams, miningParams,
MAINNET_NETWORK_ID,
nodeKeys); nodeKeys);
} }
@ -106,7 +106,6 @@ public class MainnetPantheonController implements PantheonController<Void, EthHa
final GenesisConfig<Void> genesisConfig, final GenesisConfig<Void> genesisConfig,
final SynchronizerConfiguration taintedSyncConfig, final SynchronizerConfiguration taintedSyncConfig,
final MiningParameters miningParams, final MiningParameters miningParams,
final int networkId,
final KeyPair nodeKeys) final KeyPair nodeKeys)
throws IOException { throws IOException {
final RocksDbKeyValueStorage kv = final RocksDbKeyValueStorage kv =
@ -131,9 +130,16 @@ public class MainnetPantheonController implements PantheonController<Void, EthHa
genesisConfig.getChainId(), genesisConfig.getChainId(),
fastSyncEnabled, fastSyncEnabled,
syncConfig.downloaderParallelism()); syncConfig.downloaderParallelism());
final SyncState syncState =
new SyncState(
protocolContext.getBlockchain(), ethProtocolManager.ethContext().getEthPeers());
final Synchronizer synchronizer = final Synchronizer synchronizer =
new DefaultSynchronizer<>( new DefaultSynchronizer<>(
syncConfig, protocolSchedule, protocolContext, ethProtocolManager.ethContext()); syncConfig,
protocolSchedule,
protocolContext,
ethProtocolManager.ethContext(),
syncState);
final TransactionPool transactionPool = final TransactionPool transactionPool =
TransactionPoolFactory.createTransactionPool( TransactionPoolFactory.createTransactionPool(
@ -153,7 +159,7 @@ public class MainnetPantheonController implements PantheonController<Void, EthHa
new SystemClock())); new SystemClock()));
final EthHashMiningCoordinator miningCoordinator = final EthHashMiningCoordinator miningCoordinator =
new EthHashMiningCoordinator(protocolContext.getBlockchain(), executor); new EthHashMiningCoordinator(protocolContext.getBlockchain(), executor, syncState);
miningCoordinator.addMinedBlockObserver(ethProtocolManager); miningCoordinator.addMinedBlockObserver(ethProtocolManager);
if (miningParams.isMiningEnabled()) { if (miningParams.isMiningEnabled()) {
miningCoordinator.enable(); miningCoordinator.enable();

@ -19,8 +19,8 @@ import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockCreator; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractBlockCreator;
import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator; import tech.pegasys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator;
import tech.pegasys.pantheon.ethereum.blockcreation.BlockMiner; import tech.pegasys.pantheon.ethereum.blockcreation.BlockMiner;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Synchronizer; import tech.pegasys.pantheon.ethereum.core.Synchronizer;
import tech.pegasys.pantheon.ethereum.core.TransactionPool; import tech.pegasys.pantheon.ethereum.core.TransactionPool;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
@ -58,7 +58,6 @@ public interface PantheonController<C, M extends BlockMiner<C, ? extends Abstrac
GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions)), GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions)),
syncConfig, syncConfig,
miningParameters, miningParameters,
networkId,
nodeKeys); nodeKeys);
} else if (configOptions.containsKey("ibft")) { } else if (configOptions.containsKey("ibft")) {
return IbftPantheonController.init( return IbftPantheonController.init(

@ -97,7 +97,6 @@ public final class RunnerTest {
GenesisConfig.mainnet(), GenesisConfig.mainnet(),
fastSyncConfig, fastSyncConfig,
new MiningParametersTestBuilder().enabled(false).build(), new MiningParametersTestBuilder().enabled(false).build(),
NETWORK_ID,
aheadDbNodeKeys)) { aheadDbNodeKeys)) {
setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext()); setupState(blockCount, controller.getProtocolSchedule(), controller.getProtocolContext());
} }
@ -109,7 +108,6 @@ public final class RunnerTest {
GenesisConfig.mainnet(), GenesisConfig.mainnet(),
fastSyncConfig, fastSyncConfig,
new MiningParametersTestBuilder().enabled(false).build(), new MiningParametersTestBuilder().enabled(false).build(),
NETWORK_ID,
aheadDbNodeKeys); aheadDbNodeKeys);
final String listenHost = InetAddress.getLoopbackAddress().getHostAddress(); final String listenHost = InetAddress.getLoopbackAddress().getHostAddress();
final ExecutorService executorService = Executors.newFixedThreadPool(2); final ExecutorService executorService = Executors.newFixedThreadPool(2);
@ -143,7 +141,6 @@ public final class RunnerTest {
GenesisConfig.mainnet(), GenesisConfig.mainnet(),
fastSyncConfig, fastSyncConfig,
new MiningParametersTestBuilder().enabled(false).build(), new MiningParametersTestBuilder().enabled(false).build(),
NETWORK_ID,
behindDbNodeKeys); behindDbNodeKeys);
final Runner runnerBehind = final Runner runnerBehind =
runnerBuilder.build( runnerBuilder.build(

@ -30,8 +30,8 @@ import tech.pegasys.pantheon.PantheonInfo;
import tech.pegasys.pantheon.cli.EthNetworkConfig.Builder; import tech.pegasys.pantheon.cli.EthNetworkConfig.Builder;
import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis; import tech.pegasys.pantheon.consensus.clique.jsonrpc.CliqueRpcApis;
import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis; import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftRpcApis;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;

@ -19,8 +19,8 @@ import tech.pegasys.pantheon.controller.MainnetPantheonController;
import tech.pegasys.pantheon.controller.PantheonController; import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.blockcreation.EthHashBlockMiner; import tech.pegasys.pantheon.ethereum.blockcreation.EthHashBlockMiner;
import tech.pegasys.pantheon.ethereum.blockcreation.MiningParameters;
import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig;
import tech.pegasys.pantheon.ethereum.core.MiningParameters;
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule;
@ -72,7 +72,6 @@ public final class BlockchainImporterTest {
genesisConfig, genesisConfig,
SynchronizerConfiguration.builder().build(), SynchronizerConfiguration.builder().build(),
miningParams, miningParams,
10,
keyPair); keyPair);
final BlockchainImporter.ImportResult result = final BlockchainImporter.ImportResult result =
blockImporter.importBlockchain(source, ctrl, true, 1, 1, false, false, null); blockImporter.importBlockchain(source, ctrl, true, 1, 1, false, false, null);

@ -24,6 +24,7 @@ include 'ethereum:mock-p2p'
include 'ethereum:jsonrpc' include 'ethereum:jsonrpc'
include 'ethereum:referencetests' include 'ethereum:referencetests'
include 'ethereum:core' include 'ethereum:core'
include 'ethereum:blockcreation'
include 'ethereum:rlp' include 'ethereum:rlp'
include 'ethereum:eth' include 'ethereum:eth'
include 'ethereum:trie' include 'ethereum:trie'

Loading…
Cancel
Save