From 2b661e738221980b5d55ca4ec80a6e23ca736409 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Tue, 13 Nov 2018 11:31:00 +1000 Subject: [PATCH] Common protocol schedule config handling (#250) * Introduce ProtocolScheduleBuilder and use it for Clique, MainNet, IBFT and dev. * Remove default milestone blocks and simplify MainnetProtocolSchedule. All milestone blocks must now be defined in the genesis file (previously ethash chains would get Mainnet milestone blocks by default). --- config/build.gradle | 3 + .../pantheon/config/GenesisConfigFile.java | 2 +- .../pantheon/config/GenesisConfigOptions.java | 73 ++--------- .../config/JsonGenesisConfigOptions.java | 102 +++++++++++++++ .../config/StubGenesisConfigOptions.java | 122 ++++++++++++++++++ .../clique/CliqueProtocolSchedule.java | 69 +++++----- .../consensus/clique/CliqueProtocolSpecs.java | 87 ------------- .../clique/CliqueProtocolScheduleTest.java | 16 ++- .../clique/CliqueProtocolSpecsTest.java | 57 -------- .../blockcreation/CliqueBlockCreatorTest.java | 16 +-- .../ibftlegacy/IbftProtocolSchedule.java | 45 +++++-- .../ibftlegacy/IbftProtocolSpecs.java | 63 --------- ethereum/blockcreation/build.gradle | 1 + .../EthHashBlockCreatorTest.java | 9 +- ethereum/core/build.gradle | 4 + .../DevelopmentProtocolSchedule.java | 16 +-- .../development/DevelopmentProtocolSpecs.java | 36 ------ .../mainnet/MainnetProtocolSchedule.java | 89 +------------ .../mainnet/MainnetProtocolSpecs.java | 90 +------------ .../mainnet/ProtocolScheduleBuilder.java | 96 ++++++++++++++ .../core/ExecutionContextTestFixture.java | 10 +- .../mainnet/MainnetProtocolScheduleTest.java | 43 ++---- .../vm/ReferenceTestProtocolSchedules.java | 78 +++-------- .../pantheon/ethereum/vm/VMReferenceTest.java | 2 +- ...stantinopleSStoreOperationGasCostTest.java | 4 +- ethereum/jsonrpc/build.gradle | 3 + .../jsonrpc/JsonRpcHttpServiceTest.java | 4 +- .../controller/MainnetPantheonController.java | 5 +- 28 files changed, 511 insertions(+), 634 deletions(-) create mode 100644 config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java create mode 100644 config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java delete mode 100644 consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecs.java delete mode 100644 consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecsTest.java delete mode 100644 consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSpecs.java delete mode 100644 ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSpecs.java create mode 100644 ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java diff --git a/config/build.gradle b/config/build.gradle index 536905c4c2..6f53cc7b4b 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -35,3 +35,6 @@ dependencies { testImplementation 'org.mockito:mockito-core' testImplementation 'junit:junit' } + +configurations { testArtifacts } +artifacts { testSupportArtifacts testSupportJar } diff --git a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigFile.java b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigFile.java index b45ae9587a..3ea6e3aee6 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigFile.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigFile.java @@ -59,7 +59,7 @@ public class GenesisConfigFile { } public GenesisConfigOptions getConfigOptions() { - return new GenesisConfigOptions(configRoot.getJsonObject("config")); + return new JsonGenesisConfigOptions(configRoot.getJsonObject("config")); } public Stream getAllocations() { 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 c94fc3f995..e59637caa8 100644 --- a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java +++ b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java @@ -15,76 +15,29 @@ package tech.pegasys.pantheon.config; import java.util.OptionalInt; import java.util.OptionalLong; -import io.vertx.core.json.JsonObject; +public interface GenesisConfigOptions { -public class GenesisConfigOptions { + boolean isEthHash(); - private static final String ETHASH_CONFIG_KEY = "ethash"; - private static final String IBFT_CONFIG_KEY = "ibft"; - private static final String CLIQUE_CONFIG_KEY = "clique"; - private final JsonObject configRoot; + boolean isIbft(); - GenesisConfigOptions(final JsonObject configRoot) { - this.configRoot = configRoot != null ? configRoot : new JsonObject(); - } + boolean isClique(); - public boolean isEthHash() { - return configRoot.containsKey(ETHASH_CONFIG_KEY); - } + IbftConfigOptions getIbftConfigOptions(); - public boolean isIbft() { - return configRoot.containsKey(IBFT_CONFIG_KEY); - } + CliqueConfigOptions getCliqueConfigOptions(); - public boolean isClique() { - return configRoot.containsKey(CLIQUE_CONFIG_KEY); - } + OptionalLong getHomesteadBlockNumber(); - public IbftConfigOptions getIbftConfigOptions() { - return isIbft() - ? new IbftConfigOptions(configRoot.getJsonObject(IBFT_CONFIG_KEY)) - : IbftConfigOptions.DEFAULT; - } + OptionalLong getDaoForkBlock(); - public CliqueConfigOptions getCliqueConfigOptions() { - return isClique() - ? new CliqueConfigOptions(configRoot.getJsonObject(CLIQUE_CONFIG_KEY)) - : CliqueConfigOptions.DEFAULT; - } + OptionalLong getTangerineWhistleBlockNumber(); - public OptionalLong getHomesteadBlockNumber() { - return getOptionalLong("homesteadblock"); - } + OptionalLong getSpuriousDragonBlockNumber(); - public OptionalLong getDaoForkBlock() { - return getOptionalLong("daoforkblock"); - } + OptionalLong getByzantiumBlockNumber(); - public OptionalLong getTangerineWhistleBlockNumber() { - return getOptionalLong("eip150block"); - } + OptionalLong getConstantinopleBlockNumber(); - public OptionalLong getSpuriousDragonBlockNumber() { - return getOptionalLong("eip158block"); - } - - public OptionalLong getByzantiumBlockNumber() { - return getOptionalLong("byzantiumblock"); - } - - public OptionalLong getConstantinopleBlockNumber() { - return getOptionalLong("constantinopleblock"); - } - - public OptionalInt getChainId() { - return configRoot.containsKey("chainid") - ? OptionalInt.of(configRoot.getInteger("chainid")) - : OptionalInt.empty(); - } - - private OptionalLong getOptionalLong(final String key) { - return configRoot.containsKey(key) - ? OptionalLong.of(configRoot.getLong(key)) - : OptionalLong.empty(); - } + OptionalInt getChainId(); } diff --git a/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java new file mode 100644 index 0000000000..f5385ae265 --- /dev/null +++ b/config/src/main/java/tech/pegasys/pantheon/config/JsonGenesisConfigOptions.java @@ -0,0 +1,102 @@ +/* + * 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.config; + +import java.util.OptionalInt; +import java.util.OptionalLong; + +import io.vertx.core.json.JsonObject; + +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 CLIQUE_CONFIG_KEY = "clique"; + private final JsonObject configRoot; + + JsonGenesisConfigOptions(final JsonObject configRoot) { + this.configRoot = configRoot != null ? configRoot : new JsonObject(); + } + + @Override + public boolean isEthHash() { + return configRoot.containsKey(ETHASH_CONFIG_KEY); + } + + @Override + public boolean isIbft() { + return configRoot.containsKey(IBFT_CONFIG_KEY); + } + + @Override + public boolean isClique() { + return configRoot.containsKey(CLIQUE_CONFIG_KEY); + } + + @Override + public IbftConfigOptions getIbftConfigOptions() { + return isIbft() + ? new IbftConfigOptions(configRoot.getJsonObject(IBFT_CONFIG_KEY)) + : IbftConfigOptions.DEFAULT; + } + + @Override + public CliqueConfigOptions getCliqueConfigOptions() { + return isClique() + ? new CliqueConfigOptions(configRoot.getJsonObject(CLIQUE_CONFIG_KEY)) + : CliqueConfigOptions.DEFAULT; + } + + @Override + public OptionalLong getHomesteadBlockNumber() { + return getOptionalLong("homesteadblock"); + } + + @Override + public OptionalLong getDaoForkBlock() { + return getOptionalLong("daoforkblock"); + } + + @Override + public OptionalLong getTangerineWhistleBlockNumber() { + return getOptionalLong("eip150block"); + } + + @Override + public OptionalLong getSpuriousDragonBlockNumber() { + return getOptionalLong("eip158block"); + } + + @Override + public OptionalLong getByzantiumBlockNumber() { + return getOptionalLong("byzantiumblock"); + } + + @Override + public OptionalLong getConstantinopleBlockNumber() { + return getOptionalLong("constantinopleblock"); + } + + @Override + public OptionalInt getChainId() { + return configRoot.containsKey("chainid") + ? OptionalInt.of(configRoot.getInteger("chainid")) + : OptionalInt.empty(); + } + + private OptionalLong getOptionalLong(final String key) { + return configRoot.containsKey(key) + ? OptionalLong.of(configRoot.getLong(key)) + : OptionalLong.empty(); + } +} 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 new file mode 100644 index 0000000000..d057f9e493 --- /dev/null +++ b/config/src/test-support/java/tech/pegasys/pantheon/config/StubGenesisConfigOptions.java @@ -0,0 +1,122 @@ +/* + * 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.config; + +import java.util.OptionalInt; +import java.util.OptionalLong; + +public class StubGenesisConfigOptions implements GenesisConfigOptions { + + private OptionalLong homesteadBlockNumber = OptionalLong.empty(); + private OptionalLong daoForkBlock = OptionalLong.empty(); + private OptionalLong tangerineWhistleBlockNumber = OptionalLong.empty(); + private OptionalLong spuriousDragonBlockNumber = OptionalLong.empty(); + private OptionalLong byzantiumBlockNumber = OptionalLong.empty(); + private OptionalLong constantinopleBlockNumber = OptionalLong.empty(); + private OptionalInt chainId = OptionalInt.empty(); + + @Override + public boolean isEthHash() { + return true; + } + + @Override + public boolean isIbft() { + return false; + } + + @Override + public boolean isClique() { + return false; + } + + @Override + public IbftConfigOptions getIbftConfigOptions() { + return IbftConfigOptions.DEFAULT; + } + + @Override + public CliqueConfigOptions getCliqueConfigOptions() { + return CliqueConfigOptions.DEFAULT; + } + + @Override + public OptionalLong getHomesteadBlockNumber() { + return homesteadBlockNumber; + } + + @Override + public OptionalLong getDaoForkBlock() { + return daoForkBlock; + } + + @Override + public OptionalLong getTangerineWhistleBlockNumber() { + return tangerineWhistleBlockNumber; + } + + @Override + public OptionalLong getSpuriousDragonBlockNumber() { + return spuriousDragonBlockNumber; + } + + @Override + public OptionalLong getByzantiumBlockNumber() { + return byzantiumBlockNumber; + } + + @Override + public OptionalLong getConstantinopleBlockNumber() { + return constantinopleBlockNumber; + } + + @Override + public OptionalInt getChainId() { + return chainId; + } + + public StubGenesisConfigOptions homesteadBlock(final long blockNumber) { + homesteadBlockNumber = OptionalLong.of(blockNumber); + return this; + } + + public StubGenesisConfigOptions daoForkBlock(final long blockNumber) { + daoForkBlock = OptionalLong.of(blockNumber); + return this; + } + + public StubGenesisConfigOptions eip150Block(final long blockNumber) { + tangerineWhistleBlockNumber = OptionalLong.of(blockNumber); + return this; + } + + public StubGenesisConfigOptions eip158Block(final long blockNumber) { + spuriousDragonBlockNumber = OptionalLong.of(blockNumber); + return this; + } + + public StubGenesisConfigOptions byzantiumBlock(final long blockNumber) { + byzantiumBlockNumber = OptionalLong.of(blockNumber); + return this; + } + + public StubGenesisConfigOptions constantinopleBlock(final long blockNumber) { + constantinopleBlockNumber = OptionalLong.of(blockNumber); + return this; + } + + public StubGenesisConfigOptions chainId(final int chainId) { + this.chainId = OptionalInt.of(chainId); + return this; + } +} diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java index 747283c434..acb4f440ad 100644 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java +++ b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java @@ -12,12 +12,20 @@ */ package tech.pegasys.pantheon.consensus.clique; +import static tech.pegasys.pantheon.consensus.clique.BlockHeaderValidationRulesetFactory.cliqueBlockHeaderValidator; + import tech.pegasys.pantheon.config.CliqueConfigOptions; import tech.pegasys.pantheon.config.GenesisConfigOptions; +import tech.pegasys.pantheon.consensus.common.EpochManager; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; +import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Util; -import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; +import tech.pegasys.pantheon.ethereum.core.Wei; +import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockBodyValidator; +import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockImporter; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; /** Defines the protocol behaviours for a blockchain using Clique. */ public class CliqueProtocolSchedule { @@ -27,44 +35,33 @@ public class CliqueProtocolSchedule { public static ProtocolSchedule create( final GenesisConfigOptions config, final KeyPair nodeKeys) { - // Get Config Data final CliqueConfigOptions cliqueConfig = config.getCliqueConfigOptions(); - final long epochLength = cliqueConfig.getEpochLength(); - final long blockPeriod = cliqueConfig.getBlockPeriodSeconds(); - final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID); - - final MutableProtocolSchedule protocolSchedule = - new MutableProtocolSchedule<>(chainId); - // TODO(tmm) replace address with passed in node data (coming later) - final CliqueProtocolSpecs specs = - new CliqueProtocolSpecs( - blockPeriod, - epochLength, - Util.publicKeyToAddress(nodeKeys.getPublicKey()), - protocolSchedule); + final Address localNodeAddress = Util.publicKeyToAddress(nodeKeys.getPublicKey()); - protocolSchedule.putMilestone(0, specs.frontier()); - - config - .getHomesteadBlockNumber() - .ifPresent(blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.homestead())); - config - .getTangerineWhistleBlockNumber() - .ifPresent( - blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.tangerineWhistle())); - config - .getSpuriousDragonBlockNumber() - .ifPresent( - blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.spuriousDragon())); - config - .getByzantiumBlockNumber() - .ifPresent(blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.byzantium())); - config - .getConstantinopleBlockNumber() - .ifPresent( - blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.constantinople())); + final EpochManager epochManager = new EpochManager(cliqueConfig.getEpochLength()); + return new ProtocolScheduleBuilder<>( + config, + DEFAULT_CHAIN_ID, + builder -> + applyCliqueSpecificModifications( + epochManager, cliqueConfig.getBlockPeriodSeconds(), localNodeAddress, builder)) + .createProtocolSchedule(); + } - return protocolSchedule; + private static ProtocolSpecBuilder applyCliqueSpecificModifications( + final EpochManager epochManager, + final long secondsBetweenBlocks, + final Address localNodeAddress, + final ProtocolSpecBuilder specBuilder) { + return specBuilder + .changeConsensusContextType( + difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), + difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), + MainnetBlockBodyValidator::new, + MainnetBlockImporter::new, + new CliqueDifficultyCalculator(localNodeAddress)) + .blockReward(Wei.ZERO) + .miningBeneficiaryCalculator(CliqueHelpers::getProposerOfBlock); } } diff --git a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecs.java b/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecs.java deleted file mode 100644 index a6fc274551..0000000000 --- a/consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecs.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.consensus.clique; - -import static tech.pegasys.pantheon.consensus.clique.BlockHeaderValidationRulesetFactory.cliqueBlockHeaderValidator; - -import tech.pegasys.pantheon.consensus.common.EpochManager; -import tech.pegasys.pantheon.ethereum.core.Address; -import tech.pegasys.pantheon.ethereum.core.Wei; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockBodyValidator; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockImporter; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSpecs; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; - -/** Factory for producing Clique protocol specs for given configurations and known fork points */ -public class CliqueProtocolSpecs { - - private final long secondsBetweenBlocks; - private final long epochLength; - private final Address localNodeAddress; - private final ProtocolSchedule protocolSchedule; - - public CliqueProtocolSpecs( - final long secondsBetweenBlocks, - final long epochLength, - final Address localNodeAddress, - final ProtocolSchedule protocolSchedule) { - this.secondsBetweenBlocks = secondsBetweenBlocks; - this.epochLength = epochLength; - this.localNodeAddress = localNodeAddress; - this.protocolSchedule = protocolSchedule; - } - - public ProtocolSpec frontier() { - return applyCliqueSpecificModifications(MainnetProtocolSpecs.frontierDefinition()); - } - - public ProtocolSpec homestead() { - return applyCliqueSpecificModifications(MainnetProtocolSpecs.homesteadDefinition()); - } - - public ProtocolSpec tangerineWhistle() { - return applyCliqueSpecificModifications(MainnetProtocolSpecs.tangerineWhistleDefinition()); - } - - public ProtocolSpec spuriousDragon() { - return applyCliqueSpecificModifications( - MainnetProtocolSpecs.spuriousDragonDefinition(protocolSchedule.getChainId())); - } - - public ProtocolSpec byzantium() { - return applyCliqueSpecificModifications( - MainnetProtocolSpecs.byzantiumDefinition(protocolSchedule.getChainId())); - } - - public ProtocolSpec constantinople() { - return applyCliqueSpecificModifications( - MainnetProtocolSpecs.constantinopleDefinition(protocolSchedule.getChainId())); - } - - private ProtocolSpec applyCliqueSpecificModifications( - final ProtocolSpecBuilder specBuilder) { - final EpochManager epochManager = new EpochManager(epochLength); - return specBuilder - .changeConsensusContextType( - difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), - difficultyCalculator -> cliqueBlockHeaderValidator(secondsBetweenBlocks, epochManager), - MainnetBlockBodyValidator::new, - MainnetBlockImporter::new, - new CliqueDifficultyCalculator(localNodeAddress)) - .blockReward(Wei.ZERO) - .miningBeneficiaryCalculator(CliqueHelpers::getProposerOfBlock) - .build(protocolSchedule); - } -} diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java index b6369eefe7..fcec092441 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java @@ -17,6 +17,7 @@ import static org.assertj.core.api.Java6Assertions.assertThat; import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; +import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; @@ -24,6 +25,8 @@ import org.junit.Test; public class CliqueProtocolScheduleTest { + private static final KeyPair NODE_KEYS = KeyPair.generate(); + @Test public void protocolSpecsAreCreatedAtBlockDefinedInJson() { final String jsonInput = @@ -38,7 +41,7 @@ public class CliqueProtocolScheduleTest { final GenesisConfigOptions config = GenesisConfigFile.fromConfig(jsonInput).getConfigOptions(); final ProtocolSchedule protocolSchedule = - CliqueProtocolSchedule.create(config, KeyPair.generate()); + CliqueProtocolSchedule.create(config, NODE_KEYS); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockNumber(1); final ProtocolSpec tangerineWhistleSpec = protocolSchedule.getByBlockNumber(2); @@ -49,4 +52,15 @@ public class CliqueProtocolScheduleTest { assertThat(tangerineWhistleSpec.equals(spuriousDragonSpec)).isFalse(); assertThat(spuriousDragonSpec.equals(byzantiumSpec)).isFalse(); } + + @Test + public void parametersAlignWithMainnetWithAdjustments() { + final ProtocolSpec homestead = + CliqueProtocolSchedule.create(GenesisConfigFile.DEFAULT.getConfigOptions(), NODE_KEYS) + .getByBlockNumber(0); + + assertThat(homestead.getName()).isEqualTo("Frontier"); + assertThat(homestead.getBlockReward()).isEqualTo(Wei.ZERO); + assertThat(homestead.getDifficultyCalculator()).isInstanceOf(CliqueDifficultyCalculator.class); + } } diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecsTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecsTest.java deleted file mode 100644 index 92163c7883..0000000000 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSpecsTest.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.consensus.clique; - -import static org.assertj.core.api.Java6Assertions.assertThat; - -import tech.pegasys.pantheon.ethereum.core.AddressHelpers; -import tech.pegasys.pantheon.ethereum.core.Wei; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSpecs; -import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; - -import org.junit.Test; - -public class CliqueProtocolSpecsTest { - - private static final int CHAIN_ID = 5; - CliqueProtocolSpecs protocolSpecs = - new CliqueProtocolSpecs( - 15, 30_000, AddressHelpers.ofValue(5), new MutableProtocolSchedule<>(CHAIN_ID)); - - @Test - public void homsteadParametersAlignWithMainnetWithAdjustments() { - final ProtocolSpec homestead = protocolSpecs.homestead(); - - assertThat(homestead.getName()).isEqualTo("Homestead"); - assertThat(homestead.getBlockReward()).isEqualTo(Wei.ZERO); - assertThat(homestead.getDifficultyCalculator()).isInstanceOf(CliqueDifficultyCalculator.class); - } - - @Test - public void allSpecsInheritFromMainnetCounterparts() { - final ProtocolSchedule mainnetProtocolSchedule = new MutableProtocolSchedule<>(CHAIN_ID); - - assertThat(protocolSpecs.frontier().getName()) - .isEqualTo(MainnetProtocolSpecs.frontier(mainnetProtocolSchedule).getName()); - assertThat(protocolSpecs.homestead().getName()) - .isEqualTo(MainnetProtocolSpecs.homestead(mainnetProtocolSchedule).getName()); - assertThat(protocolSpecs.tangerineWhistle().getName()) - .isEqualTo(MainnetProtocolSpecs.tangerineWhistle(mainnetProtocolSchedule).getName()); - assertThat(protocolSpecs.spuriousDragon().getName()) - .isEqualTo(MainnetProtocolSpecs.spuriousDragon(1, mainnetProtocolSchedule).getName()); - assertThat(protocolSpecs.byzantium().getName()) - .isEqualTo(MainnetProtocolSpecs.byzantium(1, mainnetProtocolSchedule).getName()); - } -} diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java index 10f5c81541..a3e094aea7 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueBlockCreatorTest.java @@ -23,7 +23,7 @@ import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueHelpers; -import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSpecs; +import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.clique.TestHelpers; import tech.pegasys.pantheon.consensus.clique.VoteTallyCache; import tech.pegasys.pantheon.consensus.common.VoteProposer; @@ -42,7 +42,7 @@ import tech.pegasys.pantheon.ethereum.core.PendingTransactions; import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; -import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.List; @@ -53,14 +53,12 @@ import org.junit.Test; public class CliqueBlockCreatorTest { - private static final int CHAIN_ID = 1; private final KeyPair proposerKeyPair = KeyPair.generate(); private final Address proposerAddress = Util.publicKeyToAddress(proposerKeyPair.getPublicKey()); private final KeyPair otherKeyPair = KeyPair.generate(); private final List
validatorList = Lists.newArrayList(); - private final MutableProtocolSchedule protocolSchedule = - new MutableProtocolSchedule<>(CHAIN_ID); + private ProtocolSchedule protocolSchedule; private final WorldStateArchive stateArchive = createInMemoryWorldStateArchive(); private MutableBlockchain blockchain; @@ -69,11 +67,9 @@ public class CliqueBlockCreatorTest { @Before public void setup() { - final CliqueProtocolSpecs specs = - new CliqueProtocolSpecs( - 15, 30_000, Util.publicKeyToAddress(proposerKeyPair.getPublicKey()), protocolSchedule); - - protocolSchedule.putMilestone(0, specs.frontier()); + protocolSchedule = + CliqueProtocolSchedule.create( + GenesisConfigFile.DEFAULT.getConfigOptions(), proposerKeyPair); final Address otherAddress = Util.publicKeyToAddress(otherKeyPair.getPublicKey()); validatorList.add(otherAddress); diff --git a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java index 9e15320812..f828a4b1d9 100644 --- a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java +++ b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java @@ -12,11 +12,21 @@ */ package tech.pegasys.pantheon.consensus.ibftlegacy; +import static tech.pegasys.pantheon.consensus.ibftlegacy.IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator; + import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.config.IbftConfigOptions; +import tech.pegasys.pantheon.consensus.common.EpochManager; +import tech.pegasys.pantheon.consensus.ibft.IbftBlockImporter; import tech.pegasys.pantheon.consensus.ibft.IbftContext; -import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; +import tech.pegasys.pantheon.ethereum.core.Wei; +import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockBodyValidator; +import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockImporter; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpecBuilder; + +import java.math.BigInteger; /** Defines the protocol behaviours for a blockchain using IBFT. */ public class IbftProtocolSchedule { @@ -24,17 +34,34 @@ public class IbftProtocolSchedule { private static final int DEFAULT_CHAIN_ID = 1; public static ProtocolSchedule create(final GenesisConfigOptions config) { - final long spuriousDragonBlock = config.getSpuriousDragonBlockNumber().orElse(0); final IbftConfigOptions ibftConfig = config.getIbftConfigOptions(); - final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID); final long epochLength = ibftConfig.getEpochLength(); final long blockPeriod = ibftConfig.getBlockPeriodSeconds(); + final EpochManager epochManager = new EpochManager(epochLength); + + return new ProtocolScheduleBuilder<>( + config, + DEFAULT_CHAIN_ID, + builder -> applyIbftChanges(blockPeriod, epochManager, builder)) + .createProtocolSchedule(); + } - final MutableProtocolSchedule protocolSchedule = - new MutableProtocolSchedule<>(chainId); - protocolSchedule.putMilestone( - spuriousDragonBlock, - IbftProtocolSpecs.spuriousDragon(blockPeriod, epochLength, chainId, protocolSchedule)); - return protocolSchedule; + private static ProtocolSpecBuilder applyIbftChanges( + final long secondsBetweenBlocks, + final EpochManager epochManager, + final ProtocolSpecBuilder builder) { + return builder + .changeConsensusContextType( + difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), + difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), + MainnetBlockBodyValidator::new, + (blockHeaderValidator, blockBodyValidator, blockProcessor) -> + new IbftBlockImporter( + new MainnetBlockImporter<>( + blockHeaderValidator, blockBodyValidator, blockProcessor), + new IbftVoteTallyUpdater(epochManager)), + (time, parent, protocolContext) -> BigInteger.ONE) + .blockReward(Wei.ZERO) + .blockHashFunction(IbftBlockHashing::calculateHashOfIbftBlockOnChain); } } diff --git a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSpecs.java b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSpecs.java deleted file mode 100644 index 468fb3f1e1..0000000000 --- a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSpecs.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.consensus.ibftlegacy; - -import static tech.pegasys.pantheon.consensus.ibftlegacy.IbftBlockHeaderValidationRulesetFactory.ibftBlockHeaderValidator; - -import tech.pegasys.pantheon.consensus.common.EpochManager; -import tech.pegasys.pantheon.consensus.ibft.IbftBlockImporter; -import tech.pegasys.pantheon.consensus.ibft.IbftContext; -import tech.pegasys.pantheon.ethereum.core.Wei; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockBodyValidator; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockImporter; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSpecs; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; - -import java.math.BigInteger; - -/** Factory for producing Ibft protocol specs for given configurations and known fork points */ -public class IbftProtocolSpecs { - - /** - * Produce the ProtocolSpec for an IBFT chain that uses spurious dragon milestone configuration - * - * @param secondsBetweenBlocks the block period in seconds - * @param epochLength the number of blocks in each epoch - * @param chainId the id of the Chain. - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return a configured ProtocolSpec for dealing with IBFT blocks - */ - public static ProtocolSpec spuriousDragon( - final long secondsBetweenBlocks, - final long epochLength, - final int chainId, - final ProtocolSchedule protocolSchedule) { - final EpochManager epochManager = new EpochManager(epochLength); - return MainnetProtocolSpecs.spuriousDragonDefinition(chainId) - .changeConsensusContextType( - difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), - difficultyCalculator -> ibftBlockHeaderValidator(secondsBetweenBlocks), - MainnetBlockBodyValidator::new, - (blockHeaderValidator, blockBodyValidator, blockProcessor) -> - new IbftBlockImporter( - new MainnetBlockImporter<>( - blockHeaderValidator, blockBodyValidator, blockProcessor), - new IbftVoteTallyUpdater(epochManager)), - (time, parent, protocolContext) -> BigInteger.ONE) - .blockReward(Wei.ZERO) - .blockHashFunction(IbftBlockHashing::calculateHashOfIbftBlockOnChain) - .name("IBFT") - .build(protocolSchedule); - } -} diff --git a/ethereum/blockcreation/build.gradle b/ethereum/blockcreation/build.gradle index 7422551f99..9631c9bbfe 100644 --- a/ethereum/blockcreation/build.gradle +++ b/ethereum/blockcreation/build.gradle @@ -23,6 +23,7 @@ dependencies { testImplementation 'org.assertj:assertj-core' testImplementation 'org.awaitility:awaitility' testImplementation 'org.mockito:mockito-core' + testImplementation project(path: ':config', configuration: 'testSupportArtifacts') testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts') } diff --git a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java index 09a94a039e..4ec2f5ea04 100644 --- a/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java +++ b/ethereum/blockcreation/src/test/java/tech/pegasys/pantheon/ethereum/blockcreation/EthHashBlockCreatorTest.java @@ -12,6 +12,7 @@ */ package tech.pegasys.pantheon.ethereum.blockcreation; +import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.ExecutionContextTestFixture; @@ -19,11 +20,12 @@ import tech.pegasys.pantheon.ethereum.core.PendingTransactions; 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.MainnetProtocolSchedule; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import tech.pegasys.pantheon.ethereum.mainnet.ValidationTestUtils; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.io.IOException; +import java.util.function.Function; import com.google.common.collect.Lists; import org.assertj.core.api.Assertions; @@ -43,7 +45,10 @@ public class EthHashBlockCreatorTest { private final ExecutionContextTestFixture executionContextTestFixture = ExecutionContextTestFixture.builder() - .protocolSchedule(MainnetProtocolSchedule.create(2, 3, 10, 11, 12, -1, 42)) + .protocolSchedule( + new ProtocolScheduleBuilder<>( + GenesisConfigFile.DEFAULT.getConfigOptions(), 42, Function.identity()) + .createProtocolSchedule()) .build(); @Test diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index 1842799870..69bf6f1147 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -36,17 +36,20 @@ dependencies { runtime 'org.apache.logging.log4j:log4j-core' testImplementation project(path:':ethereum:referencetests', configuration: 'testOutput') + testImplementation project( path: ':config', configuration: 'testSupportArtifacts') testImplementation project(':testutil') testImplementation 'org.assertj:assertj-core' testImplementation 'org.mockito:mockito-core' testImplementation 'junit:junit' + integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') integrationTestImplementation 'org.assertj:assertj-core' integrationTestImplementation 'org.mockito:mockito-core' integrationTestImplementation 'junit:junit' testSupportImplementation project(':testutil') + testSupportImplementation project( path: ':config', configuration: 'testSupportArtifacts') testSupportImplementation 'org.assertj:assertj-core' testSupportImplementation 'org.mockito:mockito-core' @@ -54,6 +57,7 @@ dependencies { jmhImplementation project(':util') jmhImplementation project( path: ':ethereum:core', configuration: 'testSupportArtifacts') + jmhImplementation project(path: ':config', configuration: 'testSupportArtifacts') jmhImplementation project(':crypto') jmhImplementation project(':ethereum:rlp') jmhImplementation project(':ethereum:trie') diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSchedule.java index f3647d5531..dda7cf7d28 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSchedule.java @@ -15,19 +15,17 @@ package tech.pegasys.pantheon.ethereum.development; import static tech.pegasys.pantheon.ethereum.mainnet.MainnetTransactionValidator.NO_CHAIN_ID; import tech.pegasys.pantheon.config.GenesisConfigOptions; -import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; -/** - * A mock ProtocolSchedule which behaves similarly to Byzantium (but for all blocks), albeit with a - * much reduced difficulty (which supports testing on CPU alone). - */ +/** A ProtocolSchedule which behaves similarly to MainNet, but with a much reduced difficulty. */ public class DevelopmentProtocolSchedule { public static ProtocolSchedule create(final GenesisConfigOptions config) { - final Integer chainId = config.getChainId().orElse(NO_CHAIN_ID); - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(chainId); - protocolSchedule.putMilestone(0, DevelopmentProtocolSpecs.first(chainId, protocolSchedule)); - return protocolSchedule; + return new ProtocolScheduleBuilder<>( + config, + NO_CHAIN_ID, + builder -> builder.difficultyCalculator(DevelopmentDifficultyCalculators.DEVELOPER)) + .createProtocolSchedule(); } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSpecs.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSpecs.java deleted file mode 100644 index 4466b6ddc7..0000000000 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/development/DevelopmentProtocolSpecs.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.development; - -import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSpecs; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; - -/** - * Provides a protocol specification which is suitable for use on private, PoW networks, where block - * mining is performed on CPUs alone. - */ -public class DevelopmentProtocolSpecs { - - /* - * The DevelopmentProtocolSpecification is the same as the byzantium spec, but with a much reduced - * difficulty calculator (to support CPU mining). - */ - public static ProtocolSpec first( - final Integer chainId, final ProtocolSchedule protocolSchedule) { - return MainnetProtocolSpecs.byzantiumDefinition(chainId) - .difficultyCalculator(DevelopmentDifficultyCalculators.DEVELOPER) - .name("first") - .build(protocolSchedule); - } -} diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java index 2a24ecce8a..b2a5739dbf 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java @@ -12,77 +12,18 @@ */ package tech.pegasys.pantheon.ethereum.mainnet; +import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.GenesisConfigOptions; +import java.util.function.Function; + /** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */ public class MainnetProtocolSchedule { - private static final long DEFAULT_HOMESTEAD_BLOCK_NUMBER = 1_150_000L; - private static final long DEFAULT_DAO_BLOCK_NUMBER = 1_920_000L; - private static final long DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER = 2_463_000L; - private static final long DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER = 2_675_000L; - private static final long DEFAULT_BYZANTIUM_BLOCK_NUMBER = 4_730_000L; - // Start of Constantinople has not yet been set. - private static final long DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER = -1L; public static final int DEFAULT_CHAIN_ID = 1; - /** - * Creates a mainnet protocol schedule with milestones starting at the specified block numbers - * - * @param homesteadBlockNumber Block number at which to start the homestead fork - * @param daoBlockNumber Block number at which to start the dao fork - * @param tangerineWhistleBlockNumber Block number at which to start the tangerine whistle fork - * @param spuriousDragonBlockNumber Block number at which to start the spurious dragon fork - * @param byzantiumBlockNumber Block number at which to start the byzantium fork - * @param constantinopleBlockNumber Block number at which to start the constantinople fork - * @param chainId ID of the blockchain - * @return MainnetProtocolSchedule return newly instantiated protocol schedule - */ - public static ProtocolSchedule create( - final long homesteadBlockNumber, - final long daoBlockNumber, - final long tangerineWhistleBlockNumber, - final long spuriousDragonBlockNumber, - final long byzantiumBlockNumber, - final long constantinopleBlockNumber, - final int chainId) { - - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(chainId); - protocolSchedule.putMilestone(0, MainnetProtocolSpecs.frontier(protocolSchedule)); - final ProtocolSpec homestead = MainnetProtocolSpecs.homestead(protocolSchedule); - protocolSchedule.putMilestone(homesteadBlockNumber, homestead); - if (daoBlockNumber != 0) { - protocolSchedule.putMilestone( - daoBlockNumber, MainnetProtocolSpecs.daoRecoveryInit(protocolSchedule)); - protocolSchedule.putMilestone( - daoBlockNumber + 1, MainnetProtocolSpecs.daoRecoveryTransition(protocolSchedule)); - protocolSchedule.putMilestone(daoBlockNumber + 10, homestead); - } - protocolSchedule.putMilestone( - tangerineWhistleBlockNumber, MainnetProtocolSpecs.tangerineWhistle(protocolSchedule)); - protocolSchedule.putMilestone( - spuriousDragonBlockNumber, MainnetProtocolSpecs.spuriousDragon(chainId, protocolSchedule)); - protocolSchedule.putMilestone( - byzantiumBlockNumber, MainnetProtocolSpecs.byzantium(chainId, protocolSchedule)); - - if (constantinopleBlockNumber >= 0) { - protocolSchedule.putMilestone( - constantinopleBlockNumber, - MainnetProtocolSpecs.constantinople(chainId, protocolSchedule)); - } - - return protocolSchedule; - } - public static ProtocolSchedule create() { - return create( - DEFAULT_HOMESTEAD_BLOCK_NUMBER, - DEFAULT_DAO_BLOCK_NUMBER, - DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER, - DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER, - DEFAULT_BYZANTIUM_BLOCK_NUMBER, - DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER, - DEFAULT_CHAIN_ID); + return fromConfig(GenesisConfigFile.mainnet().getConfigOptions()); } /** @@ -93,25 +34,7 @@ public class MainnetProtocolSchedule { * @return A configured mainnet protocol schedule */ public static ProtocolSchedule fromConfig(final GenesisConfigOptions config) { - final long homesteadBlockNumber = - config.getHomesteadBlockNumber().orElse(DEFAULT_HOMESTEAD_BLOCK_NUMBER); - final long daoBlockNumber = config.getDaoForkBlock().orElse(DEFAULT_DAO_BLOCK_NUMBER); - final long tangerineWhistleBlockNumber = - config.getTangerineWhistleBlockNumber().orElse(DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER); - final long spuriousDragonBlockNumber = - config.getSpuriousDragonBlockNumber().orElse(DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER); - final long byzantiumBlockNumber = - config.getByzantiumBlockNumber().orElse(DEFAULT_BYZANTIUM_BLOCK_NUMBER); - final long constantinopleBlockNumber = - config.getConstantinopleBlockNumber().orElse(DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER); - final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID); - return create( - homesteadBlockNumber, - daoBlockNumber, - tangerineWhistleBlockNumber, - spuriousDragonBlockNumber, - byzantiumBlockNumber, - constantinopleBlockNumber, - chainId); + return new ProtocolScheduleBuilder<>(config, DEFAULT_CHAIN_ID, Function.identity()) + .createProtocolSchedule(); } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java index bedcf75089..ebd5c29139 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSpecs.java @@ -94,26 +94,6 @@ public abstract class MainnetProtocolSpecs { .name("Frontier"); } - /** - * Returns the Frontier milestone protocol spec. - * - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the Frontier milestone protocol spec - */ - public static ProtocolSpec frontier(final ProtocolSchedule protocolSchedule) { - return frontierDefinition().build(protocolSchedule); - } - - /** - * Returns the Homestead milestone protocol spec. - * - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the Homestead milestone protocol spec - */ - public static ProtocolSpec homestead(final ProtocolSchedule protocolSchedule) { - return homesteadDefinition().build(protocolSchedule); - } - public static ProtocolSpecBuilder homesteadDefinition() { return frontierDefinition() .gasCalculator(HomesteadGasCalculator::new) @@ -128,17 +108,7 @@ public abstract class MainnetProtocolSpecs { .name("Homestead"); } - /** - * Returns the initial DAO block milestone protocol spec. - * - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the initial DAO block milestone protocol spec - */ - public static ProtocolSpec daoRecoveryInit(final ProtocolSchedule protocolSchedule) { - return daoRecoveryInitDefinition().build(protocolSchedule); - } - - private static ProtocolSpecBuilder daoRecoveryInitDefinition() { + public static ProtocolSpecBuilder daoRecoveryInitDefinition() { return homesteadDefinition() .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::createDaoValidator) .blockProcessorBuilder( @@ -155,28 +125,10 @@ public abstract class MainnetProtocolSpecs { .name("DaoRecoveryInit"); } - /** - * Returns the DAO block transition segment milestone protocol spec. - * - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the DAO block transition segment milestone protocol spec - */ - public static ProtocolSpec daoRecoveryTransition( - final ProtocolSchedule protocolSchedule) { + public static ProtocolSpecBuilder daoRecoveryTransitionDefinition() { return daoRecoveryInitDefinition() .blockProcessorBuilder(MainnetBlockProcessor::new) - .name("DaoRecoveryTransition") - .build(protocolSchedule); - } - - /** - * Returns the Tangerine Whistle milestone protocol spec. - * - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the Tangerine Whistle milestone protocol spec - */ - public static ProtocolSpec tangerineWhistle(final ProtocolSchedule protocolSchedule) { - return tangerineWhistleDefinition().build(protocolSchedule); + .name("DaoRecoveryTransition"); } public static ProtocolSpecBuilder tangerineWhistleDefinition() { @@ -185,18 +137,6 @@ public abstract class MainnetProtocolSpecs { .name("TangerineWhistle"); } - /** - * Returns the Spurious Dragon milestone protocol spec. - * - * @param chainId ID of the blockchain - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the Spurious Dragon milestone protocol spec - */ - public static ProtocolSpec spuriousDragon( - final int chainId, final ProtocolSchedule protocolSchedule) { - return spuriousDragonDefinition(chainId).build(protocolSchedule); - } - public static ProtocolSpecBuilder spuriousDragonDefinition(final int chainId) { return tangerineWhistleDefinition() .gasCalculator(SpuriousDragonGasCalculator::new) @@ -231,18 +171,6 @@ public abstract class MainnetProtocolSpecs { .name("SpuriousDragon"); } - /** - * Returns the Byzantium milestone protocol spec. - * - * @param chainId ID of the blockchain - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the Byzantium milestone protocol spec - */ - public static ProtocolSpec byzantium( - final int chainId, final ProtocolSchedule protocolSchedule) { - return byzantiumDefinition(chainId).build(protocolSchedule); - } - public static ProtocolSpecBuilder byzantiumDefinition(final int chainId) { return spuriousDragonDefinition(chainId) .evmBuilder(MainnetEvmRegistries::byzantium) @@ -254,18 +182,6 @@ public abstract class MainnetProtocolSpecs { .name("Byzantium"); } - /** - * Returns the Constantinople milestone protocol spec. - * - * @param chainId ID of the blockchain - * @param protocolSchedule the {@link ProtocolSchedule} this spec will be part of - * @return the Constantinople milestone protocol spec - */ - public static ProtocolSpec constantinople( - final int chainId, final ProtocolSchedule protocolSchedule) { - return constantinopleDefinition(chainId).build(protocolSchedule); - } - public static ProtocolSpecBuilder constantinopleDefinition(final int chainId) { return byzantiumDefinition(chainId) .difficultyCalculator(MainnetDifficultyCalculators.CONSTANTINOPLE) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java new file mode 100644 index 0000000000..33d5f6e9b5 --- /dev/null +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolScheduleBuilder.java @@ -0,0 +1,96 @@ +/* + * 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.mainnet; + +import tech.pegasys.pantheon.config.GenesisConfigOptions; + +import java.util.OptionalLong; +import java.util.function.Function; + +public class ProtocolScheduleBuilder { + + private final GenesisConfigOptions config; + private final Function, ProtocolSpecBuilder> protocolSpecAdapter; + private final int defaultChainId; + + public ProtocolScheduleBuilder( + final GenesisConfigOptions config, + final int defaultChainId, + final Function, ProtocolSpecBuilder> protocolSpecAdapter) { + this.config = config; + this.protocolSpecAdapter = protocolSpecAdapter; + this.defaultChainId = defaultChainId; + } + + public ProtocolSchedule createProtocolSchedule() { + final int chainId = config.getChainId().orElse(defaultChainId); + final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(chainId); + + addProtocolSpec( + protocolSchedule, OptionalLong.of(0), MainnetProtocolSpecs.frontierDefinition()); + addProtocolSpec( + protocolSchedule, + config.getHomesteadBlockNumber(), + MainnetProtocolSpecs.homesteadDefinition()); + + config + .getDaoForkBlock() + .ifPresent( + daoBlockNumber -> { + if (daoBlockNumber > 0) { + final ProtocolSpec originalProtocolSpec = + protocolSchedule.getByBlockNumber(daoBlockNumber); + addProtocolSpec( + protocolSchedule, + OptionalLong.of(daoBlockNumber), + MainnetProtocolSpecs.daoRecoveryInitDefinition()); + addProtocolSpec( + protocolSchedule, + OptionalLong.of(daoBlockNumber + 1), + MainnetProtocolSpecs.daoRecoveryTransitionDefinition()); + + // Return to the previous protocol spec after the dao fork has completed. + protocolSchedule.putMilestone(daoBlockNumber + 10, originalProtocolSpec); + } + }); + + addProtocolSpec( + protocolSchedule, + config.getTangerineWhistleBlockNumber(), + MainnetProtocolSpecs.tangerineWhistleDefinition()); + addProtocolSpec( + protocolSchedule, + config.getSpuriousDragonBlockNumber(), + MainnetProtocolSpecs.spuriousDragonDefinition(chainId)); + addProtocolSpec( + protocolSchedule, + config.getByzantiumBlockNumber(), + MainnetProtocolSpecs.byzantiumDefinition(chainId)); + addProtocolSpec( + protocolSchedule, + config.getConstantinopleBlockNumber(), + MainnetProtocolSpecs.constantinopleDefinition(chainId)); + + return protocolSchedule; + } + + private void addProtocolSpec( + final MutableProtocolSchedule protocolSchedule, + final OptionalLong blockNumber, + final ProtocolSpecBuilder definition) { + blockNumber.ifPresent( + number -> + protocolSchedule.putMilestone( + number, protocolSpecAdapter.apply(definition).build(protocolSchedule))); + } +} diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java index 69851c0bf3..72e21e96a5 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.ethereum.core; import tech.pegasys.pantheon.config.GenesisConfigFile; +import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.chain.GenesisState; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; @@ -20,13 +21,15 @@ import tech.pegasys.pantheon.ethereum.db.DefaultMutableBlockchain; import tech.pegasys.pantheon.ethereum.db.KeyValueStoragePrefixedKeyBlockchainStorage; import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import tech.pegasys.pantheon.ethereum.worldstate.DefaultMutableWorldState; import tech.pegasys.pantheon.ethereum.worldstate.KeyValueStorageWorldStateStorage; import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; +import java.util.function.Function; + public class ExecutionContextTestFixture { private final Block genesis; @@ -106,7 +109,10 @@ public class ExecutionContextTestFixture { public ExecutionContextTestFixture build() { if (protocolSchedule == null) { - protocolSchedule = MainnetProtocolSchedule.create(0, 0, 0, 0, 0, 0, 42); + protocolSchedule = + new ProtocolScheduleBuilder<>( + new StubGenesisConfigOptions().constantinopleBlock(0), 42, Function.identity()) + .createProtocolSchedule(); } if (keyValueStorage == null) { keyValueStorage = new InMemoryKeyValueStorage(); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java index a78d96ad1f..9b69aae64a 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java @@ -14,6 +14,9 @@ package tech.pegasys.pantheon.ethereum.mainnet; import tech.pegasys.pantheon.config.GenesisConfigFile; +import java.nio.charset.StandardCharsets; + +import com.google.common.io.Resources; import io.vertx.core.json.JsonObject; import org.assertj.core.api.Assertions; import org.junit.Test; @@ -38,36 +41,12 @@ public class MainnetProtocolScheduleTest { } @Test - public void shouldReturnCorrectProtocolSpecsWhenCustomNumbersAreUsed() { - final ProtocolSchedule sched = MainnetProtocolSchedule.create(2, 3, 14, 15, 16, 18, 1); - Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("Frontier"); - Assertions.assertThat(sched.getByBlockNumber(2).getName()).isEqualTo("Homestead"); - Assertions.assertThat(sched.getByBlockNumber(3).getName()).isEqualTo("DaoRecoveryInit"); - Assertions.assertThat(sched.getByBlockNumber(4).getName()).isEqualTo("DaoRecoveryTransition"); - Assertions.assertThat(sched.getByBlockNumber(13).getName()).isEqualTo("Homestead"); - Assertions.assertThat(sched.getByBlockNumber(14).getName()).isEqualTo("TangerineWhistle"); - Assertions.assertThat(sched.getByBlockNumber(15).getName()).isEqualTo("SpuriousDragon"); - Assertions.assertThat(sched.getByBlockNumber(16).getName()).isEqualTo("Byzantium"); - Assertions.assertThat(sched.getByBlockNumber(18).getName()).isEqualTo("Constantinople"); - } - - @Test - public void shouldReturnDefaultProtocolSpecsWhenEmptyJsonConfigIsUsed() { + public void shouldOnlyUseFrontierWhenEmptyJsonConfigIsUsed() { final JsonObject json = new JsonObject("{}"); final ProtocolSchedule sched = MainnetProtocolSchedule.fromConfig(GenesisConfigFile.fromConfig(json).getConfigOptions()); Assertions.assertThat(sched.getByBlockNumber(1L).getName()).isEqualTo("Frontier"); - Assertions.assertThat(sched.getByBlockNumber(1_150_000L).getName()).isEqualTo("Homestead"); - Assertions.assertThat(sched.getByBlockNumber(1_920_000L).getName()) - .isEqualTo("DaoRecoveryInit"); - Assertions.assertThat(sched.getByBlockNumber(1_920_001L).getName()) - .isEqualTo("DaoRecoveryTransition"); - Assertions.assertThat(sched.getByBlockNumber(1_920_010L).getName()).isEqualTo("Homestead"); - Assertions.assertThat(sched.getByBlockNumber(2_463_000L).getName()) - .isEqualTo("TangerineWhistle"); - Assertions.assertThat(sched.getByBlockNumber(2_675_000L).getName()).isEqualTo("SpuriousDragon"); - Assertions.assertThat(sched.getByBlockNumber(4_730_000L).getName()).isEqualTo("Byzantium"); - Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()).isEqualTo("Byzantium"); + Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()).isEqualTo("Frontier"); } @Test @@ -89,13 +68,19 @@ public class MainnetProtocolScheduleTest { } @Test - public void shouldCreateRopstenConfig() { + public void shouldCreateRopstenConfig() throws Exception { final ProtocolSchedule sched = - MainnetProtocolSchedule.create(0, 0, 0, 10, 1700000, -1, 3); + MainnetProtocolSchedule.fromConfig( + GenesisConfigFile.fromConfig( + Resources.toString( + Resources.getResource("ropsten.json"), StandardCharsets.UTF_8)) + .getConfigOptions()); Assertions.assertThat(sched.getByBlockNumber(0).getName()).isEqualTo("TangerineWhistle"); Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("TangerineWhistle"); Assertions.assertThat(sched.getByBlockNumber(10).getName()).isEqualTo("SpuriousDragon"); Assertions.assertThat(sched.getByBlockNumber(1700000).getName()).isEqualTo("Byzantium"); - Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()).isEqualTo("Byzantium"); + Assertions.assertThat(sched.getByBlockNumber(4230000).getName()).isEqualTo("Constantinople"); + Assertions.assertThat(sched.getByBlockNumber(Long.MAX_VALUE).getName()) + .isEqualTo("Constantinople"); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java index d28d21228e..afd1f769c8 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/ReferenceTestProtocolSchedules.java @@ -12,10 +12,10 @@ */ package tech.pegasys.pantheon.ethereum.vm; -import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSpecs; -import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; +import tech.pegasys.pantheon.config.GenesisConfigOptions; +import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolScheduleBuilder; import java.util.Map; import java.util.function.Function; @@ -28,26 +28,24 @@ public class ReferenceTestProtocolSchedules { public static ReferenceTestProtocolSchedules create() { final ImmutableMap.Builder> builder = ImmutableMap.builder(); - builder.put("Frontier", createSchedule(MainnetProtocolSpecs::frontier)); - builder.put("FrontierToHomesteadAt5", frontierToHomesteadAt5()); - builder.put("Homestead", createSchedule(MainnetProtocolSpecs::homestead)); - builder.put("HomesteadToEIP150At5", homesteadToEip150At5()); - builder.put("HomesteadToDaoAt5", homesteadToDaoAt5()); - builder.put("EIP150", createSchedule(MainnetProtocolSpecs::tangerineWhistle)); + builder.put("Frontier", createSchedule(new StubGenesisConfigOptions())); builder.put( - "EIP158", - createSchedule( - protocolSpecLookup -> - MainnetProtocolSpecs.spuriousDragon(CHAIN_ID, protocolSpecLookup))); - builder.put("EIP158ToByzantiumAt5", eip158ToByzantiumAt5()); + "FrontierToHomesteadAt5", createSchedule(new StubGenesisConfigOptions().homesteadBlock(5))); + builder.put("Homestead", createSchedule(new StubGenesisConfigOptions().homesteadBlock(0))); builder.put( - "Byzantium", - createSchedule( - protocolSchedule -> MainnetProtocolSpecs.byzantium(CHAIN_ID, protocolSchedule))); + "HomesteadToEIP150At5", + createSchedule(new StubGenesisConfigOptions().homesteadBlock(0).eip150Block(5))); builder.put( - "Constantinople", - createSchedule( - protocolSchedule -> MainnetProtocolSpecs.constantinople(CHAIN_ID, protocolSchedule))); + "HomesteadToDaoAt5", + createSchedule(new StubGenesisConfigOptions().homesteadBlock(0).daoForkBlock(5))); + builder.put("EIP150", createSchedule(new StubGenesisConfigOptions().eip150Block(0))); + builder.put("EIP158", createSchedule(new StubGenesisConfigOptions().eip158Block(0))); + builder.put( + "EIP158ToByzantiumAt5", + createSchedule(new StubGenesisConfigOptions().eip158Block(0).byzantiumBlock(5))); + builder.put("Byzantium", createSchedule(new StubGenesisConfigOptions().byzantiumBlock(0))); + builder.put( + "Constantinople", createSchedule(new StubGenesisConfigOptions().constantinopleBlock(0))); return new ReferenceTestProtocolSchedules(builder.build()); } @@ -61,42 +59,8 @@ public class ReferenceTestProtocolSchedules { return schedules.get(name); } - private static ProtocolSchedule createSchedule( - final Function, ProtocolSpec> specCreator) { - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(CHAIN_ID); - protocolSchedule.putMilestone(0, specCreator.apply(protocolSchedule)); - return protocolSchedule; - } - - private static ProtocolSchedule frontierToHomesteadAt5() { - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(CHAIN_ID); - protocolSchedule.putMilestone(0, MainnetProtocolSpecs.frontier(protocolSchedule)); - protocolSchedule.putMilestone(5, MainnetProtocolSpecs.homestead(protocolSchedule)); - return protocolSchedule; - } - - private static ProtocolSchedule homesteadToEip150At5() { - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(CHAIN_ID); - protocolSchedule.putMilestone(0, MainnetProtocolSpecs.homestead(protocolSchedule)); - protocolSchedule.putMilestone(5, MainnetProtocolSpecs.tangerineWhistle(protocolSchedule)); - return protocolSchedule; - } - - private static ProtocolSchedule homesteadToDaoAt5() { - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(CHAIN_ID); - final ProtocolSpec homestead = MainnetProtocolSpecs.homestead(protocolSchedule); - protocolSchedule.putMilestone(0, homestead); - protocolSchedule.putMilestone(5, MainnetProtocolSpecs.daoRecoveryInit(protocolSchedule)); - protocolSchedule.putMilestone(6, MainnetProtocolSpecs.daoRecoveryTransition(protocolSchedule)); - protocolSchedule.putMilestone(15, homestead); - return protocolSchedule; - } - - private static ProtocolSchedule eip158ToByzantiumAt5() { - final MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(CHAIN_ID); - protocolSchedule.putMilestone( - 0, MainnetProtocolSpecs.spuriousDragon(CHAIN_ID, protocolSchedule)); - protocolSchedule.putMilestone(5, MainnetProtocolSpecs.byzantium(CHAIN_ID, protocolSchedule)); - return protocolSchedule; + private static ProtocolSchedule createSchedule(final GenesisConfigOptions options) { + return new ProtocolScheduleBuilder<>(options, CHAIN_ID, Function.identity()) + .createProtocolSchedule(); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java index 1e44310fe2..f5c878e336 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/VMReferenceTest.java @@ -115,7 +115,7 @@ public class VMReferenceTest extends AbstractRetryingTest { final EnvironmentInformation execEnv = spec.getExec(); final ProtocolSpec protocolSpec = - MainnetProtocolSpecs.frontier(new MutableProtocolSchedule<>(CHAIN_ID)); + MainnetProtocolSpecs.frontierDefinition().build(new MutableProtocolSchedule<>(CHAIN_ID)); final TestBlockchain blockchain = new TestBlockchain(execEnv.getBlockHeader().getNumber()); final MessageFrame frame = diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java index 6384e7a2d8..239ec05260 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/operations/ConstantinopleSStoreOperationGasCostTest.java @@ -14,6 +14,7 @@ package tech.pegasys.pantheon.ethereum.vm.operations; import static org.assertj.core.api.Assertions.assertThat; +import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.TestCodeExecutor; import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; @@ -31,8 +32,9 @@ import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class ConstantinopleSStoreOperationGasCostTest { + private static final ProtocolSchedule protocolSchedule = - MainnetProtocolSchedule.create(0, 0, 0, 0, 0, 0, 1); + MainnetProtocolSchedule.fromConfig(new StubGenesisConfigOptions().constantinopleBlock(0)); @Parameters(name = "Code: {0}, Original: {1}") public static Object[][] scenarios() { diff --git a/ethereum/jsonrpc/build.gradle b/ethereum/jsonrpc/build.gradle index 7d74adfbe9..641887a3ce 100644 --- a/ethereum/jsonrpc/build.gradle +++ b/ethereum/jsonrpc/build.gradle @@ -35,6 +35,8 @@ dependencies { testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts') testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') + testImplementation project(':config') + testImplementation project(path: ':config', configuration: 'testSupportArtifacts') testImplementation project(':services:kvstore') testImplementation project(':testutil') @@ -46,6 +48,7 @@ dependencies { testImplementation 'io.vertx:vertx-unit' integrationTestImplementation project(':config') + integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts') integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') integrationTestImplementation project(':services:kvstore') diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java index b15794721f..0cccb441fe 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcHttpServiceTest.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.ethereum.blockcreation.EthHashMiningCoordinator; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; @@ -113,7 +114,8 @@ public class JsonRpcHttpServiceTest { peerDiscoveryMock, blockchainQueries, synchronizer, - MainnetProtocolSchedule.create(0, 0, 0, 0, 0, 0, CHAIN_ID), + MainnetProtocolSchedule.fromConfig( + new StubGenesisConfigOptions().constantinopleBlock(0).chainId(CHAIN_ID)), mock(FilterManager.class), mock(TransactionPool.class), mock(EthHashMiningCoordinator.class), diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java index 944c4a94aa..4f1ed72ffb 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java @@ -99,10 +99,11 @@ public class MainnetPantheonController implements PantheonController { public static PantheonController mainnet(final Path home) throws IOException { final MiningParameters miningParams = new MiningParameters(null, null, null, false); final KeyPair nodeKeys = loadKeyPair(home); + final GenesisConfigFile genesisConfig = GenesisConfigFile.mainnet(); return init( home, - GenesisConfigFile.mainnet(), - MainnetProtocolSchedule.create(), + genesisConfig, + MainnetProtocolSchedule.fromConfig(genesisConfig.getConfigOptions()), SynchronizerConfiguration.builder().build(), miningParams, nodeKeys);