diff --git a/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java index 57a0a7cc6d..f73638a00c 100644 --- a/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java +++ b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java @@ -2,7 +2,6 @@ package net.consensys.pantheon.consensus.clique.blockcreation; import net.consensys.pantheon.consensus.clique.CliqueContext; import net.consensys.pantheon.consensus.clique.CliqueHelpers; -import net.consensys.pantheon.consensus.common.ValidatorProvider; import net.consensys.pantheon.ethereum.ProtocolContext; import net.consensys.pantheon.ethereum.blockcreation.AbstractBlockScheduler; import net.consensys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; @@ -30,8 +29,6 @@ public class CliqueBlockMiner extends BlockMiner validators = Lists.newArrayList(); + final BytesValue vanityDataToInsert = createCorrectlySizedVanityData(); // Building ON TOP of canonical head, if the next block is epoch, include validators. if (epochManager.isEpochBlock(parentHeader.getNumber() + 1)) { - VoteTally voteTally = + final VoteTally voteTally = protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parentHeader); validators.addAll(voteTally.getCurrentValidators()); } - CliqueExtraData extraData = new CliqueExtraData(vanityData, null, validators); + final CliqueExtraData extraData = new CliqueExtraData(vanityDataToInsert, null, validators); return extraData.encode(); } + + private BytesValue createCorrectlySizedVanityData() { + int vanityPadding = Math.max(0, CliqueExtraData.EXTRA_VANITY_LENGTH - vanityData.size()); + return BytesValues.concatenate(BytesValue.wrap(new byte[vanityPadding]), vanityData) + .slice(0, CliqueExtraData.EXTRA_VANITY_LENGTH); + } } diff --git a/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueMiningCoordinator.java b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueMiningCoordinator.java new file mode 100644 index 0000000000..179d8ad441 --- /dev/null +++ b/consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueMiningCoordinator.java @@ -0,0 +1,21 @@ +package net.consensys.pantheon.consensus.clique.blockcreation; + +import net.consensys.pantheon.consensus.clique.CliqueContext; +import net.consensys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator; +import net.consensys.pantheon.ethereum.chain.Blockchain; + +import java.util.Optional; + +public class CliqueMiningCoordinator + extends AbstractMiningCoordinator { + + public CliqueMiningCoordinator(final Blockchain blockchain, final CliqueMinerExecutor executor) { + super(blockchain, executor); + } + + @Override + protected void haltCurrentMiningOperation() { + currentRunningMiner.ifPresent(CliqueBlockMiner::cancel); + currentRunningMiner = Optional.empty(); + } +} diff --git a/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/AbstractMiningCoordinator.java b/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/AbstractMiningCoordinator.java index a7d8f58541..e3909adcbd 100644 --- a/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/AbstractMiningCoordinator.java +++ b/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/AbstractMiningCoordinator.java @@ -33,9 +33,25 @@ public abstract class AbstractMiningCoordinator< this.blockchain.observeBlockAdded(this); } - public abstract void enable(); + public void enable() { + synchronized (this) { + if (isEnabled) { + return; + } + startAsyncMiningOperation(); + isEnabled = true; + } + } - public abstract void disable(); + public void disable() { + synchronized (this) { + if (!isEnabled) { + return; + } + haltCurrentMiningOperation(); + isEnabled = false; + } + } public boolean isRunning() { synchronized (this) { diff --git a/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java b/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java index 368e1adba0..2d57b539e9 100644 --- a/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java +++ b/ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java @@ -24,28 +24,6 @@ public class EthHashMiningCoordinator extends AbstractMiningCoordinator genesisConfig, final ProtocolContext context, @@ -72,9 +85,16 @@ public class CliquePantheonController final Path home, final GenesisConfig genesisConfig, final SynchronizerConfiguration taintedSyncConfig, + final MiningParameters miningParams, + final JsonObject cliqueConfig, final int networkId, final KeyPair nodeKeys) throws IOException { + final long blocksPerEpoch = cliqueConfig.getLong("epoch", EPOCH_LENGTH_DEFAULT); + final long secondsBetweenBlocks = + cliqueConfig.getLong("period", SECONDS_BETWEEN_BLOCKS_DEFAULT); + + final EpochManager epochManger = new EpochManager(blocksPerEpoch); final RocksDbKeyValueStorage kv = RocksDbKeyValueStorage.create(Files.createDirectories(home.resolve(DATABASE_PATH))); final ProtocolSchedule protocolSchedule = genesisConfig.getProtocolSchedule(); @@ -87,7 +107,6 @@ public class CliquePantheonController final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); genesisConfig.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH)); - final EpochManager epochManger = new EpochManager(30_000); final ProtocolContext protocolContext = new ProtocolContext<>( blockchain, @@ -113,6 +132,28 @@ public class CliquePantheonController TransactionPoolFactory.createTransactionPool( protocolSchedule, protocolContext, ethProtocolManager.ethContext()); + final ExecutorService minerThreadPool = Executors.newCachedThreadPool(); + CliqueMinerExecutor miningExecutor = + new CliqueMinerExecutor( + protocolContext, + minerThreadPool, + protocolSchedule, + transactionPool.getPendingTransactions(), + nodeKeys, + miningParams, + new CliqueBlockScheduler( + new SystemClock(), + protocolContext.getConsensusState().getVoteTallyCache(), + Util.publicKeyToAddress(nodeKeys.getPublicKey()), + secondsBetweenBlocks), + epochManger); + CliqueMiningCoordinator miningCoordinator = + new CliqueMiningCoordinator(blockchain, miningExecutor); + miningCoordinator.addMinedBlockObserver(ethProtocolManager); + + // Clique mining is implicitly enabled. + miningCoordinator.enable(); + return new CliquePantheonController( genesisConfig, protocolContext, @@ -120,7 +161,16 @@ public class CliquePantheonController synchronizer, nodeKeys, transactionPool, - kv::close); + () -> { + miningCoordinator.disable(); + minerThreadPool.shutdownNow(); + try { + minerThreadPool.awaitTermination(5, TimeUnit.SECONDS); + } catch (final InterruptedException e) { + LOG.error("Failed to shutdown miner executor"); + } + kv.close(); + }); } @Override diff --git a/pantheon/src/main/java/net/consensys/pantheon/controller/PantheonController.java b/pantheon/src/main/java/net/consensys/pantheon/controller/PantheonController.java index a4acd16ce7..e5cc0b4521 100644 --- a/pantheon/src/main/java/net/consensys/pantheon/controller/PantheonController.java +++ b/pantheon/src/main/java/net/consensys/pantheon/controller/PantheonController.java @@ -62,6 +62,8 @@ public interface PantheonController the consensus context type + * @param the type of miner being used within the executing pantheon * @return the import result * @throws IOException On Failure */ diff --git a/pantheon/src/main/java/net/consensys/pantheon/util/BlockchainImporter.java b/pantheon/src/main/java/net/consensys/pantheon/util/BlockchainImporter.java index 6c174456b0..0d6349d5e7 100644 --- a/pantheon/src/main/java/net/consensys/pantheon/util/BlockchainImporter.java +++ b/pantheon/src/main/java/net/consensys/pantheon/util/BlockchainImporter.java @@ -79,6 +79,7 @@ public class BlockchainImporter extends BlockImporter { * Imports blockchain from file as concatenated RLP sections * * @param the consensus context type + * @param the type of miner being used within the executing pantheon * @param dataFilePath Path to the file containing the dataFilePath * @param pantheonController the PantheonController that defines blockchain behavior * @param isSkipHeaderValidation if true, header validation is skipped. This must only be used