diff --git a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java index e59637caa8..8141836faa 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java @@ -21,12 +21,16 @@ public interface GenesisConfigOptions { boolean isIbft(); + boolean isRevisedIbft(); + boolean isClique(); IbftConfigOptions getIbftConfigOptions(); CliqueConfigOptions getCliqueConfigOptions(); + IbftConfigOptions getRevisedIbftConfigOptions(); + OptionalLong getHomesteadBlockNumber(); OptionalLong getDaoForkBlock(); diff --git a/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java index f5385ae265..8bc1cb4866 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java @@ -21,6 +21,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { private static final String ETHASH_CONFIG_KEY = "ethash"; private static final String IBFT_CONFIG_KEY = "ibft"; + private static final String REVISED_IBFT_CONFIG_KEY = "revisedibft"; private static final String CLIQUE_CONFIG_KEY = "clique"; private final JsonObject configRoot; @@ -43,6 +44,11 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { return configRoot.containsKey(CLIQUE_CONFIG_KEY); } + @Override + public boolean isRevisedIbft() { + return configRoot.containsKey(REVISED_IBFT_CONFIG_KEY); + } + @Override public IbftConfigOptions getIbftConfigOptions() { return isIbft() @@ -50,6 +56,13 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { : IbftConfigOptions.DEFAULT; } + @Override + public IbftConfigOptions getRevisedIbftConfigOptions() { + return isRevisedIbft() + ? new IbftConfigOptions(configRoot.getJsonObject(REVISED_IBFT_CONFIG_KEY)) + : IbftConfigOptions.DEFAULT; + } + @Override public CliqueConfigOptions getCliqueConfigOptions() { return isClique() diff --git a/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java b/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java index d057f9e493..3e7788efce 100644 --- a/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java +++ b/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java @@ -40,6 +40,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { return false; } + @Override + public boolean isRevisedIbft() { + return false; + } + @Override public IbftConfigOptions getIbftConfigOptions() { return IbftConfigOptions.DEFAULT; @@ -50,6 +55,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions { return CliqueConfigOptions.DEFAULT; } + @Override + public IbftConfigOptions getRevisedIbftConfigOptions() { + return IbftConfigOptions.DEFAULT; + } + @Override public OptionalLong getHomesteadBlockNumber() { return homesteadBlockNumber; diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java new file mode 100644 index 0000000000..0f0c94c32a --- /dev/null +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java @@ -0,0 +1,234 @@ +/* + * 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.controller; + +import static org.apache.logging.log4j.LogManager.getLogger; + +import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.config.GenesisConfigOptions; +import tech.pegasys.pantheon.config.IbftConfigOptions; +import tech.pegasys.pantheon.consensus.common.EpochManager; +import tech.pegasys.pantheon.consensus.common.VoteProposer; +import tech.pegasys.pantheon.consensus.common.VoteTally; +import tech.pegasys.pantheon.consensus.common.VoteTallyUpdater; +import tech.pegasys.pantheon.consensus.ibft.IbftContext; +import tech.pegasys.pantheon.consensus.ibft.jsonrpc.IbftJsonRpcMethodsFactory; +import tech.pegasys.pantheon.consensus.ibftlegacy.IbftLegacyBlockInterface; +import tech.pegasys.pantheon.consensus.ibftlegacy.IbftProtocolSchedule; +import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64Protocol; +import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64ProtocolManager; +import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; +import tech.pegasys.pantheon.ethereum.ProtocolContext; +import tech.pegasys.pantheon.ethereum.blockcreation.MiningCoordinator; +import tech.pegasys.pantheon.ethereum.chain.GenesisState; +import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; +import tech.pegasys.pantheon.ethereum.core.Hash; +import tech.pegasys.pantheon.ethereum.core.Synchronizer; +import tech.pegasys.pantheon.ethereum.core.TransactionPool; +import tech.pegasys.pantheon.ethereum.db.BlockchainStorage; +import tech.pegasys.pantheon.ethereum.db.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; +import tech.pegasys.pantheon.ethereum.eth.EthProtocol; +import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager; +import tech.pegasys.pantheon.ethereum.eth.sync.DefaultSynchronizer; +import tech.pegasys.pantheon.ethereum.eth.sync.SyncMode; +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.jsonrpc.RpcApi; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.JsonRpcMethod; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.ethereum.p2p.api.ProtocolManager; +import tech.pegasys.pantheon.ethereum.p2p.config.SubProtocolConfiguration; +import tech.pegasys.pantheon.ethereum.p2p.wire.SubProtocol; +import tech.pegasys.pantheon.ethereum.storage.StorageProvider; +import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +import org.apache.logging.log4j.Logger; + +public class IbftLegacyPantheonController implements PantheonController { + + private static final Logger LOG = getLogger(); + private final GenesisConfigOptions genesisConfig; + private final ProtocolSchedule protocolSchedule; + private final ProtocolContext context; + private final Synchronizer synchronizer; + private final SubProtocol ethSubProtocol; + private final ProtocolManager ethProtocolManager; + private final KeyPair keyPair; + private final TransactionPool transactionPool; + private final Runnable closer; + + IbftLegacyPantheonController( + final GenesisConfigOptions genesisConfig, + final ProtocolSchedule protocolSchedule, + final ProtocolContext context, + final SubProtocol ethSubProtocol, + final ProtocolManager ethProtocolManager, + final Synchronizer synchronizer, + final KeyPair keyPair, + final TransactionPool transactionPool, + final Runnable closer) { + + this.genesisConfig = genesisConfig; + this.protocolSchedule = protocolSchedule; + this.context = context; + this.ethSubProtocol = ethSubProtocol; + this.ethProtocolManager = ethProtocolManager; + this.synchronizer = synchronizer; + this.keyPair = keyPair; + this.transactionPool = transactionPool; + this.closer = closer; + } + + public static PantheonController init( + final StorageProvider storageProvider, + final GenesisConfigFile genesisConfig, + final SynchronizerConfiguration taintedSyncConfig, + final boolean ottomanTestnetOperation, + final int networkId, + final KeyPair nodeKeys) { + final ProtocolSchedule protocolSchedule = + IbftProtocolSchedule.create(genesisConfig.getConfigOptions()); + final GenesisState genesisState = GenesisState.fromConfig(genesisConfig, protocolSchedule); + final BlockchainStorage blockchainStorage = + storageProvider.createBlockchainStorage(protocolSchedule); + final MutableBlockchain blockchain = + new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage); + + final WorldStateStorage worldStateStorage = storageProvider.createWorldStateStorage(); + final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); + genesisState.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH)); + + final IbftConfigOptions ibftConfig = genesisConfig.getConfigOptions().getIbftConfigOptions(); + final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength()); + + final VoteTally voteTally = + new VoteTallyUpdater(epochManager, new IbftLegacyBlockInterface()) + .buildVoteTallyFromBlockchain(blockchain); + + final VoteProposer voteProposer = new VoteProposer(); + + final ProtocolContext protocolContext = + new ProtocolContext<>( + blockchain, worldStateArchive, new IbftContext(voteTally, voteProposer)); + + final SynchronizerConfiguration syncConfig = taintedSyncConfig.validated(blockchain); + final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST); + final EthProtocolManager ethProtocolManager; + final SubProtocol ethSubProtocol; + if (ottomanTestnetOperation) { + LOG.info("Operating on Ottoman testnet."); + ethSubProtocol = Istanbul64Protocol.get(); + ethProtocolManager = + new Istanbul64ProtocolManager( + protocolContext.getBlockchain(), + networkId, + fastSyncEnabled, + syncConfig.downloaderParallelism()); + } else { + ethSubProtocol = EthProtocol.get(); + ethProtocolManager = + new EthProtocolManager( + protocolContext.getBlockchain(), + networkId, + fastSyncEnabled, + syncConfig.downloaderParallelism()); + } + + final SyncState syncState = + new SyncState( + protocolContext.getBlockchain(), ethProtocolManager.ethContext().getEthPeers()); + final Synchronizer synchronizer = + new DefaultSynchronizer<>( + syncConfig, + protocolSchedule, + protocolContext, + ethProtocolManager.ethContext(), + syncState); + + final Runnable closer = + () -> { + try { + storageProvider.close(); + } catch (final IOException e) { + LOG.error("Failed to close storage provider", e); + } + }; + + final TransactionPool transactionPool = + TransactionPoolFactory.createTransactionPool( + protocolSchedule, protocolContext, ethProtocolManager.ethContext()); + + return new IbftLegacyPantheonController( + genesisConfig.getConfigOptions(), + protocolSchedule, + protocolContext, + ethSubProtocol, + ethProtocolManager, + synchronizer, + nodeKeys, + transactionPool, + closer); + } + + @Override + public ProtocolContext getProtocolContext() { + return context; + } + + @Override + public ProtocolSchedule getProtocolSchedule() { + return protocolSchedule; + } + + @Override + public Synchronizer getSynchronizer() { + return synchronizer; + } + + @Override + public SubProtocolConfiguration subProtocolConfiguration() { + return new SubProtocolConfiguration().withSubProtocol(ethSubProtocol, ethProtocolManager); + } + + @Override + public KeyPair getLocalNodeKeyPair() { + return keyPair; + } + + @Override + public TransactionPool getTransactionPool() { + return transactionPool; + } + + @Override + public MiningCoordinator getMiningCoordinator() { + return null; + } + + @Override + public Map getAdditionalJsonRpcMethods( + final Collection enabledRpcApis) { + return new IbftJsonRpcMethodsFactory().methods(context, enabledRpcApis); + } + + @Override + public void close() { + closer.run(); + } +} diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java index b67dc0bdc0..70fe297502 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java @@ -33,8 +33,6 @@ import tech.pegasys.pantheon.consensus.ibft.protocol.IbftProtocolManager; import tech.pegasys.pantheon.consensus.ibft.protocol.IbftSubProtocol; import tech.pegasys.pantheon.consensus.ibftlegacy.IbftLegacyBlockInterface; import tech.pegasys.pantheon.consensus.ibftlegacy.IbftProtocolSchedule; -import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64Protocol; -import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64ProtocolManager; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.blockcreation.MiningCoordinator; @@ -116,7 +114,6 @@ public class IbftPantheonController implements PantheonController { final GenesisConfigFile genesisConfig, final SynchronizerConfiguration taintedSyncConfig, final MiningParameters miningParams, - final boolean ottomanTestnetOperation, final int networkId, final KeyPair nodeKeys) { final ProtocolSchedule protocolSchedule = @@ -146,26 +143,14 @@ public class IbftPantheonController implements PantheonController { final SynchronizerConfiguration syncConfig = taintedSyncConfig.validated(blockchain); final boolean fastSyncEnabled = syncConfig.syncMode().equals(SyncMode.FAST); - final EthProtocolManager ethProtocolManager; - final SubProtocol ethSubProtocol; - if (ottomanTestnetOperation) { - LOG.info("Operating on Ottoman testnet."); - ethSubProtocol = Istanbul64Protocol.get(); - ethProtocolManager = - new Istanbul64ProtocolManager( - protocolContext.getBlockchain(), - networkId, - fastSyncEnabled, - syncConfig.downloaderParallelism()); - } else { - ethSubProtocol = EthProtocol.get(); - ethProtocolManager = - new EthProtocolManager( - protocolContext.getBlockchain(), - networkId, - fastSyncEnabled, - syncConfig.downloaderParallelism()); - } + final EthProtocolManager ethProtocolManager = + new EthProtocolManager( + protocolContext.getBlockchain(), + networkId, + fastSyncEnabled, + syncConfig.downloaderParallelism()); + final SubProtocol ethSubProtocol = EthProtocol.get(); + final SyncState syncState = new SyncState( protocolContext.getBlockchain(), ethProtocolManager.ethContext().getEthPeers()); diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java index 3dbbe8f5d6..af57b872ed 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java @@ -57,12 +57,14 @@ public interface PantheonController extends Closeable { syncConfig, miningParameters, nodeKeys); - } else if (configOptions.isIbft()) { + } else if (configOptions.isRevisedIbft()) { return IbftPantheonController.init( + storageProvider, genesisConfigFile, syncConfig, miningParameters, networkId, nodeKeys); + } else if (configOptions.isIbft()) { + return IbftLegacyPantheonController.init( storageProvider, genesisConfigFile, syncConfig, - miningParameters, ottomanTestnetOperation, networkId, nodeKeys);