From 0d866cee8439549bcbca522fb22d947520661451 Mon Sep 17 00:00:00 2001 From: tmohay <37158202+rain-on@users.noreply.github.com> Date: Mon, 26 Nov 2018 11:06:15 +1100 Subject: [PATCH] Config to support IBFT original and revised (#306) With the advent of "IBFT 2.0" the config file parsing needed to be updated such that both the original IBFT, and the new variant can be uniquely identified at execution time. --- .../pantheon/config/GenesisConfigOptions.java | 4 + .../config/JsonGenesisConfigOptions.java | 13 + .../config/StubGenesisConfigOptions.java | 10 + .../IbftLegacyPantheonController.java | 234 ++++++++++++++++++ .../controller/IbftPantheonController.java | 31 +-- .../controller/PantheonController.java | 6 +- 6 files changed, 273 insertions(+), 25 deletions(-) create mode 100644 pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java 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);