Wired Mining into CliquePantheonController (#22)

This changeset allows pantheon to join, and act as a validator in a clique network.
tmohay 6 years ago committed by GitHub
parent 124b502a8f
commit 6c8422d5f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockMiner.java
  2. 2
      consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueBlockScheduler.java
  3. 12
      consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutor.java
  4. 21
      consensus/clique/src/main/java/net/consensys/pantheon/consensus/clique/blockcreation/CliqueMiningCoordinator.java
  5. 20
      ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/AbstractMiningCoordinator.java
  6. 22
      ethereum/core/src/main/java/net/consensys/pantheon/ethereum/blockcreation/EthHashMiningCoordinator.java
  7. 54
      pantheon/src/main/java/net/consensys/pantheon/controller/CliquePantheonController.java
  8. 2
      pantheon/src/main/java/net/consensys/pantheon/controller/PantheonController.java
  9. 1
      pantheon/src/main/java/net/consensys/pantheon/util/BlockImporter.java
  10. 1
      pantheon/src/main/java/net/consensys/pantheon/util/BlockchainImporter.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.CliqueContext;
import net.consensys.pantheon.consensus.clique.CliqueHelpers; 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.ProtocolContext;
import net.consensys.pantheon.ethereum.blockcreation.AbstractBlockScheduler; import net.consensys.pantheon.ethereum.blockcreation.AbstractBlockScheduler;
import net.consensys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver; import net.consensys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator.MinedBlockObserver;
@ -30,8 +29,6 @@ public class CliqueBlockMiner extends BlockMiner<CliqueContext, CliqueBlockCreat
@Override @Override
protected boolean mineBlock() throws InterruptedException { protected boolean mineBlock() throws InterruptedException {
ValidatorProvider validators =
protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parentHeader);
if (CliqueHelpers.addressIsAllowedToProduceNextBlock( if (CliqueHelpers.addressIsAllowedToProduceNextBlock(
localAddress, protocolContext, parentHeader)) { localAddress, protocolContext, parentHeader)) {
return super.mineBlock(); return super.mineBlock();

@ -17,7 +17,6 @@ public class CliqueBlockScheduler extends DefaultBlockScheduler {
private final VoteTallyCache voteTallyCache; private final VoteTallyCache voteTallyCache;
private final Address localNodeAddress; private final Address localNodeAddress;
private final long secondsBetweenBlocks;
public CliqueBlockScheduler( public CliqueBlockScheduler(
final Clock clock, final Clock clock,
@ -27,7 +26,6 @@ public class CliqueBlockScheduler extends DefaultBlockScheduler {
super(secondsBetweenBlocks, 0L, clock); super(secondsBetweenBlocks, 0L, clock);
this.voteTallyCache = voteTallyCache; this.voteTallyCache = voteTallyCache;
this.localNodeAddress = localNodeAddress; this.localNodeAddress = localNodeAddress;
this.secondsBetweenBlocks = secondsBetweenBlocks;
} }
@Override @Override

@ -17,6 +17,7 @@ import net.consensys.pantheon.ethereum.core.Util;
import net.consensys.pantheon.ethereum.mainnet.ProtocolSchedule; import net.consensys.pantheon.ethereum.mainnet.ProtocolSchedule;
import net.consensys.pantheon.util.Subscribers; import net.consensys.pantheon.util.Subscribers;
import net.consensys.pantheon.util.bytes.BytesValue; import net.consensys.pantheon.util.bytes.BytesValue;
import net.consensys.pantheon.util.bytes.BytesValues;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -83,15 +84,22 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor<CliqueContext, Cl
public BytesValue calculateExtraData(final BlockHeader parentHeader) { public BytesValue calculateExtraData(final BlockHeader parentHeader) {
List<Address> validators = Lists.newArrayList(); List<Address> validators = Lists.newArrayList();
final BytesValue vanityDataToInsert = createCorrectlySizedVanityData();
// Building ON TOP of canonical head, if the next block is epoch, include validators. // Building ON TOP of canonical head, if the next block is epoch, include validators.
if (epochManager.isEpochBlock(parentHeader.getNumber() + 1)) { if (epochManager.isEpochBlock(parentHeader.getNumber() + 1)) {
VoteTally voteTally = final VoteTally voteTally =
protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parentHeader); protocolContext.getConsensusState().getVoteTallyCache().getVoteTallyAtBlock(parentHeader);
validators.addAll(voteTally.getCurrentValidators()); validators.addAll(voteTally.getCurrentValidators());
} }
CliqueExtraData extraData = new CliqueExtraData(vanityData, null, validators); final CliqueExtraData extraData = new CliqueExtraData(vanityDataToInsert, null, validators);
return extraData.encode(); 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);
}
} }

@ -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<CliqueContext, CliqueBlockMiner> {
public CliqueMiningCoordinator(final Blockchain blockchain, final CliqueMinerExecutor executor) {
super(blockchain, executor);
}
@Override
protected void haltCurrentMiningOperation() {
currentRunningMiner.ifPresent(CliqueBlockMiner::cancel);
currentRunningMiner = Optional.empty();
}
}

@ -33,9 +33,25 @@ public abstract class AbstractMiningCoordinator<
this.blockchain.observeBlockAdded(this); 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() { public boolean isRunning() {
synchronized (this) { synchronized (this) {

@ -24,28 +24,6 @@ public class EthHashMiningCoordinator extends AbstractMiningCoordinator<Void, Et
this.executor = executor; this.executor = executor;
} }
@Override
public void enable() {
synchronized (this) {
if (isEnabled) {
return;
}
startAsyncMiningOperation();
isEnabled = true;
}
}
@Override
public void disable() {
synchronized (this) {
if (!isEnabled) {
return;
}
haltCurrentMiningOperation();
isEnabled = false;
}
}
@Override @Override
public void setCoinbase(final Address coinbase) { public void setCoinbase(final Address coinbase) {
executor.setCoinbase(coinbase); executor.setCoinbase(coinbase);

@ -6,17 +6,22 @@ import net.consensys.pantheon.consensus.clique.CliqueContext;
import net.consensys.pantheon.consensus.clique.CliqueVoteTallyUpdater; import net.consensys.pantheon.consensus.clique.CliqueVoteTallyUpdater;
import net.consensys.pantheon.consensus.clique.VoteTallyCache; import net.consensys.pantheon.consensus.clique.VoteTallyCache;
import net.consensys.pantheon.consensus.clique.blockcreation.CliqueBlockMiner; import net.consensys.pantheon.consensus.clique.blockcreation.CliqueBlockMiner;
import net.consensys.pantheon.consensus.clique.blockcreation.CliqueBlockScheduler;
import net.consensys.pantheon.consensus.clique.blockcreation.CliqueMinerExecutor;
import net.consensys.pantheon.consensus.clique.blockcreation.CliqueMiningCoordinator;
import net.consensys.pantheon.consensus.common.EpochManager; import net.consensys.pantheon.consensus.common.EpochManager;
import net.consensys.pantheon.consensus.common.VoteProposer; import net.consensys.pantheon.consensus.common.VoteProposer;
import net.consensys.pantheon.crypto.SECP256K1.KeyPair; import net.consensys.pantheon.crypto.SECP256K1.KeyPair;
import net.consensys.pantheon.ethereum.ProtocolContext; import net.consensys.pantheon.ethereum.ProtocolContext;
import net.consensys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator; import net.consensys.pantheon.ethereum.blockcreation.AbstractMiningCoordinator;
import net.consensys.pantheon.ethereum.blockcreation.MiningParameters;
import net.consensys.pantheon.ethereum.chain.GenesisConfig; import net.consensys.pantheon.ethereum.chain.GenesisConfig;
import net.consensys.pantheon.ethereum.chain.MutableBlockchain; import net.consensys.pantheon.ethereum.chain.MutableBlockchain;
import net.consensys.pantheon.ethereum.core.BlockHashFunction; import net.consensys.pantheon.ethereum.core.BlockHashFunction;
import net.consensys.pantheon.ethereum.core.Hash; import net.consensys.pantheon.ethereum.core.Hash;
import net.consensys.pantheon.ethereum.core.Synchronizer; import net.consensys.pantheon.ethereum.core.Synchronizer;
import net.consensys.pantheon.ethereum.core.TransactionPool; import net.consensys.pantheon.ethereum.core.TransactionPool;
import net.consensys.pantheon.ethereum.core.Util;
import net.consensys.pantheon.ethereum.db.DefaultMutableBlockchain; import net.consensys.pantheon.ethereum.db.DefaultMutableBlockchain;
import net.consensys.pantheon.ethereum.db.WorldStateArchive; import net.consensys.pantheon.ethereum.db.WorldStateArchive;
import net.consensys.pantheon.ethereum.eth.EthProtocol; import net.consensys.pantheon.ethereum.eth.EthProtocol;
@ -31,11 +36,16 @@ import net.consensys.pantheon.ethereum.p2p.api.ProtocolManager;
import net.consensys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; import net.consensys.pantheon.ethereum.p2p.config.SubProtocolConfiguration;
import net.consensys.pantheon.ethereum.worldstate.KeyValueStorageWorldStateStorage; import net.consensys.pantheon.ethereum.worldstate.KeyValueStorageWorldStateStorage;
import net.consensys.pantheon.services.kvstore.RocksDbKeyValueStorage; import net.consensys.pantheon.services.kvstore.RocksDbKeyValueStorage;
import net.consensys.pantheon.util.time.SystemClock;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
public class CliquePantheonController public class CliquePantheonController
@ -50,6 +60,9 @@ public class CliquePantheonController
private final TransactionPool transactionPool; private final TransactionPool transactionPool;
private final Runnable closer; private final Runnable closer;
private static final long EPOCH_LENGTH_DEFAULT = 30_000L;
private static final long SECONDS_BETWEEN_BLOCKS_DEFAULT = 15L;
CliquePantheonController( CliquePantheonController(
final GenesisConfig<CliqueContext> genesisConfig, final GenesisConfig<CliqueContext> genesisConfig,
final ProtocolContext<CliqueContext> context, final ProtocolContext<CliqueContext> context,
@ -72,9 +85,16 @@ public class CliquePantheonController
final Path home, final Path home,
final GenesisConfig<CliqueContext> genesisConfig, final GenesisConfig<CliqueContext> genesisConfig,
final SynchronizerConfiguration taintedSyncConfig, final SynchronizerConfiguration taintedSyncConfig,
final MiningParameters miningParams,
final JsonObject cliqueConfig,
final int networkId, final int networkId,
final KeyPair nodeKeys) final KeyPair nodeKeys)
throws IOException { 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 = final RocksDbKeyValueStorage kv =
RocksDbKeyValueStorage.create(Files.createDirectories(home.resolve(DATABASE_PATH))); RocksDbKeyValueStorage.create(Files.createDirectories(home.resolve(DATABASE_PATH)));
final ProtocolSchedule<CliqueContext> protocolSchedule = genesisConfig.getProtocolSchedule(); final ProtocolSchedule<CliqueContext> protocolSchedule = genesisConfig.getProtocolSchedule();
@ -87,7 +107,6 @@ public class CliquePantheonController
final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage);
genesisConfig.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH)); genesisConfig.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH));
final EpochManager epochManger = new EpochManager(30_000);
final ProtocolContext<CliqueContext> protocolContext = final ProtocolContext<CliqueContext> protocolContext =
new ProtocolContext<>( new ProtocolContext<>(
blockchain, blockchain,
@ -113,6 +132,28 @@ public class CliquePantheonController
TransactionPoolFactory.createTransactionPool( TransactionPoolFactory.createTransactionPool(
protocolSchedule, protocolContext, ethProtocolManager.ethContext()); 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( return new CliquePantheonController(
genesisConfig, genesisConfig,
protocolContext, protocolContext,
@ -120,7 +161,16 @@ public class CliquePantheonController
synchronizer, synchronizer,
nodeKeys, nodeKeys,
transactionPool, 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 @Override

@ -62,6 +62,8 @@ public interface PantheonController<C, M extends BlockMiner<C, ? extends Abstrac
pantheonHome, pantheonHome,
GenesisConfig.fromConfig(config, CliqueProtocolSchedule.create(configOptions, nodeKeys)), GenesisConfig.fromConfig(config, CliqueProtocolSchedule.create(configOptions, nodeKeys)),
syncConfig, syncConfig,
miningParameters,
configOptions.getJsonObject("clique"),
networkId, networkId,
nodeKeys); nodeKeys);
} else { } else {

@ -34,6 +34,7 @@ public class BlockImporter {
* @param blocks Path to the file containing the blocks * @param blocks Path to the file containing the blocks
* @param pantheonController the PantheonController that defines blockchain behavior * @param pantheonController the PantheonController that defines blockchain behavior
* @param <C> the consensus context type * @param <C> the consensus context type
* @param <M> the type of miner being used within the executing pantheon
* @return the import result * @return the import result
* @throws IOException On Failure * @throws IOException On Failure
*/ */

@ -79,6 +79,7 @@ public class BlockchainImporter extends BlockImporter {
* Imports blockchain from file as concatenated RLP sections * Imports blockchain from file as concatenated RLP sections
* *
* @param <C> the consensus context type * @param <C> the consensus context type
* @param <M> the type of miner being used within the executing pantheon
* @param dataFilePath Path to the file containing the dataFilePath * @param dataFilePath Path to the file containing the dataFilePath
* @param pantheonController the PantheonController that defines blockchain behavior * @param pantheonController the PantheonController that defines blockchain behavior
* @param isSkipHeaderValidation if true, header validation is skipped. This must only be used * @param isSkipHeaderValidation if true, header validation is skipped. This must only be used

Loading…
Cancel
Save