From 824b56f141df4a407ceb83c68bef6cfb2800186b Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Thu, 1 Nov 2018 13:23:42 +1000 Subject: [PATCH] Add wrapper classes for config section of genesis file (#208) * Introduce classes to wrap JSON config instead of accessing it directly in multiple places. * Fix discrepancy in how CliqueProtocolSchedule and CliquePantheonController loaded the block period configuration. --- config/build.gradle | 36 +++++ .../pantheon/config/CliqueConfigOptions.java | 37 +++++ .../pantheon/config/GenesisConfigOptions.java | 98 +++++++++++++ .../pantheon/config/IbftConfigOptions.java | 42 ++++++ .../config/CliqueConfigOptionsTest.java | 70 +++++++++ .../config/GenesisConfigOptionsTest.java | 134 ++++++++++++++++++ .../config/IbftConfigOptionsTest.java | 88 ++++++++++++ consensus/clique/build.gradle | 1 + .../clique/CliqueProtocolSchedule.java | 55 +++---- .../clique/CliqueProtocolScheduleTest.java | 13 +- .../CliqueMinerExecutorTest.java | 7 +- consensus/ibftlegacy/build.gradle | 1 + .../ibftlegacy/IbftProtocolSchedule.java | 28 ++-- .../blockcreation/IbftBlockCreatorTest.java | 5 +- ethereum/core/build.gradle | 1 + .../ethereum/chain/GenesisConfig.java | 13 +- .../mainnet/MainnetProtocolSchedule.java | 18 +-- .../mainnet/MainnetProtocolScheduleTest.java | 10 +- ethereum/jsonrpc/build.gradle | 1 + .../ethereum/jsonrpc/BlockchainImporter.java | 6 +- pantheon/build.gradle | 1 + .../controller/CliquePantheonController.java | 11 +- .../controller/IbftPantheonController.java | 15 +- .../controller/PantheonController.java | 13 +- pantheon/src/test/resources/ibft_genesis.json | 8 +- settings.gradle | 1 + 26 files changed, 602 insertions(+), 111 deletions(-) create mode 100644 config/build.gradle create mode 100644 config/src/main/java/tech/pegasys/pantheon/config/CliqueConfigOptions.java create mode 100644 config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java create mode 100644 config/src/main/java/tech/pegasys/pantheon/config/IbftConfigOptions.java create mode 100644 config/src/test/java/tech/pegasys/pantheon/config/CliqueConfigOptionsTest.java create mode 100644 config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java create mode 100644 config/src/test/java/tech/pegasys/pantheon/config/IbftConfigOptionsTest.java diff --git a/config/build.gradle b/config/build.gradle new file mode 100644 index 0000000000..8ebd43abe7 --- /dev/null +++ b/config/build.gradle @@ -0,0 +1,36 @@ +/* + * 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. + */ + +apply plugin: 'java-library' + +jar { + baseName 'pantheon-config' + manifest { + attributes('Implementation-Title': baseName, + 'Implementation-Version': project.version) + } +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'io.vertx:vertx-core' + implementation 'org.apache.logging.log4j:log4j-api' + + runtime 'org.apache.logging.log4j:log4j-core' + + testImplementation project(':testutil') + + testImplementation 'org.assertj:assertj-core' + testImplementation 'org.mockito:mockito-core' + testImplementation 'junit:junit' +} diff --git a/config/src/main/java/tech/pegasys/pantheon/config/CliqueConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/CliqueConfigOptions.java new file mode 100644 index 0000000000..d716bdf356 --- /dev/null +++ b/config/src/main/java/tech/pegasys/pantheon/config/CliqueConfigOptions.java @@ -0,0 +1,37 @@ +/* + * 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 io.vertx.core.json.JsonObject; + +public class CliqueConfigOptions { + + public static final CliqueConfigOptions DEFAULT = new CliqueConfigOptions(new JsonObject()); + + private static final long DEFAULT_EPOCH_LENGTH = 30_000; + private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 15; + + private final JsonObject cliqueConfigRoot; + + public CliqueConfigOptions(final JsonObject cliqueConfigRoot) { + this.cliqueConfigRoot = cliqueConfigRoot; + } + + public long getEpochLength() { + return cliqueConfigRoot.getLong("epochLength", DEFAULT_EPOCH_LENGTH); + } + + public int getBlockPeriodSeconds() { + return cliqueConfigRoot.getInteger("blockPeriodSeconds", DEFAULT_BLOCK_PERIOD_SECONDS); + } +} diff --git a/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java new file mode 100644 index 0000000000..8b201591a8 --- /dev/null +++ b/config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java @@ -0,0 +1,98 @@ +/* + * 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 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; + + private GenesisConfigOptions(final JsonObject configRoot) { + this.configRoot = configRoot != null ? configRoot : new JsonObject(); + } + + public static GenesisConfigOptions fromGenesisConfig(final String genesisConfig) { + return fromGenesisConfig(new JsonObject(genesisConfig)); + } + + public static GenesisConfigOptions fromGenesisConfig(final JsonObject genesisConfig) { + return new GenesisConfigOptions(genesisConfig.getJsonObject("config")); + } + + public boolean isEthHash() { + return configRoot.containsKey(ETHASH_CONFIG_KEY); + } + + public boolean isIbft() { + return configRoot.containsKey(IBFT_CONFIG_KEY); + } + + public boolean isClique() { + return configRoot.containsKey(CLIQUE_CONFIG_KEY); + } + + public IbftConfigOptions getIbftConfigOptions() { + return isIbft() + ? new IbftConfigOptions(configRoot.getJsonObject(IBFT_CONFIG_KEY)) + : IbftConfigOptions.DEFAULT; + } + + public CliqueConfigOptions getCliqueConfigOptions() { + return isClique() + ? new CliqueConfigOptions(configRoot.getJsonObject(CLIQUE_CONFIG_KEY)) + : CliqueConfigOptions.DEFAULT; + } + + public OptionalLong getHomesteadBlockNumber() { + return getOptionalLong("homesteadBlock"); + } + + public OptionalLong getDaoForkBlock() { + return getOptionalLong("daoForkBlock"); + } + + public OptionalLong getTangerineWhistleBlockNumber() { + return getOptionalLong("eip150Block"); + } + + 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(); + } +} diff --git a/config/src/main/java/tech/pegasys/pantheon/config/IbftConfigOptions.java b/config/src/main/java/tech/pegasys/pantheon/config/IbftConfigOptions.java new file mode 100644 index 0000000000..54cb05cfc5 --- /dev/null +++ b/config/src/main/java/tech/pegasys/pantheon/config/IbftConfigOptions.java @@ -0,0 +1,42 @@ +/* + * 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 io.vertx.core.json.JsonObject; + +public class IbftConfigOptions { + + public static final IbftConfigOptions DEFAULT = new IbftConfigOptions(new JsonObject()); + + private static final long DEFAULT_EPOCH_LENGTH = 30_000; + private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1; + private static final int DEFAULT_ROUND_EXPIRY_MILLISECONDS = 10000; + + private final JsonObject ibftConfigRoot; + + public IbftConfigOptions(final JsonObject ibftConfigRoot) { + this.ibftConfigRoot = ibftConfigRoot; + } + + public long getEpochLength() { + return ibftConfigRoot.getLong("epochLength", DEFAULT_EPOCH_LENGTH); + } + + public int getBlockPeriodSeconds() { + return ibftConfigRoot.getInteger("blockPeriodSeconds", DEFAULT_BLOCK_PERIOD_SECONDS); + } + + public int getRequestTimeoutMillis() { + return ibftConfigRoot.getInteger("requestTimeout", DEFAULT_ROUND_EXPIRY_MILLISECONDS); + } +} diff --git a/config/src/test/java/tech/pegasys/pantheon/config/CliqueConfigOptionsTest.java b/config/src/test/java/tech/pegasys/pantheon/config/CliqueConfigOptionsTest.java new file mode 100644 index 0000000000..554eedcd6e --- /dev/null +++ b/config/src/test/java/tech/pegasys/pantheon/config/CliqueConfigOptionsTest.java @@ -0,0 +1,70 @@ +/* + * 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 static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import io.vertx.core.json.JsonObject; +import org.junit.Test; + +public class CliqueConfigOptionsTest { + + private static final long EXPECTED_DEFAULT_EPOCH_LENGTH = 30_000; + private static final int EXPECTED_DEFAULT_BLOCK_PERIOD = 15; + + @Test + public void shouldGetEpochLengthFromConfig() { + final CliqueConfigOptions config = fromConfigOptions(singletonMap("epochLength", 10_000)); + assertThat(config.getEpochLength()).isEqualTo(10_000); + } + + @Test + public void shouldFallbackToDefaultEpochLength() { + final CliqueConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getEpochLength()).isEqualTo(EXPECTED_DEFAULT_EPOCH_LENGTH); + } + + @Test + public void shouldGetDefaultEpochLengthFromDefaultConfig() { + assertThat(CliqueConfigOptions.DEFAULT.getEpochLength()) + .isEqualTo(EXPECTED_DEFAULT_EPOCH_LENGTH); + } + + @Test + public void shouldGetBlockPeriodFromConfig() { + final CliqueConfigOptions config = fromConfigOptions(singletonMap("blockPeriodSeconds", 5)); + assertThat(config.getBlockPeriodSeconds()).isEqualTo(5); + } + + @Test + public void shouldFallbackToDefaultBlockPeriod() { + final CliqueConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getBlockPeriodSeconds()).isEqualTo(EXPECTED_DEFAULT_BLOCK_PERIOD); + } + + @Test + public void shouldGetDefaultBlockPeriodFromDefaultConfig() { + assertThat(CliqueConfigOptions.DEFAULT.getBlockPeriodSeconds()) + .isEqualTo(EXPECTED_DEFAULT_BLOCK_PERIOD); + } + + private CliqueConfigOptions fromConfigOptions(final Map cliqueConfigOptions) { + return GenesisConfigOptions.fromGenesisConfig( + new JsonObject(singletonMap("config", singletonMap("clique", cliqueConfigOptions)))) + .getCliqueConfigOptions(); + } +} diff --git a/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java b/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java new file mode 100644 index 0000000000..d9b89f1f99 --- /dev/null +++ b/config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java @@ -0,0 +1,134 @@ +/* + * 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 static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collections; +import java.util.Map; + +import io.vertx.core.json.JsonObject; +import org.junit.Test; + +public class GenesisConfigOptionsTest { + + @Test + public void shouldUseEthHashWhenEthHashInConfig() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("ethash", emptyMap())); + assertThat(config.isEthHash()).isTrue(); + } + + @Test + public void shouldNotUseEthHashIfEthHashNotPresent() { + final GenesisConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.isEthHash()).isFalse(); + } + + @Test + public void shouldUseIbftWhenIbftInConfig() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("ibft", emptyMap())); + assertThat(config.isIbft()).isTrue(); + assertThat(config.getIbftConfigOptions()).isNotSameAs(IbftConfigOptions.DEFAULT); + } + + @Test + public void shouldNotUseIbftIfIbftNotPresent() { + final GenesisConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.isIbft()).isFalse(); + assertThat(config.getIbftConfigOptions()).isSameAs(IbftConfigOptions.DEFAULT); + } + + @Test + public void shouldUseCliqueWhenCliqueInConfig() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("clique", emptyMap())); + assertThat(config.isClique()).isTrue(); + assertThat(config.getCliqueConfigOptions()).isNotSameAs(CliqueConfigOptions.DEFAULT); + } + + @Test + public void shouldNotUseCliqueIfCliqueNotPresent() { + final GenesisConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.isClique()).isFalse(); + assertThat(config.getCliqueConfigOptions()).isSameAs(CliqueConfigOptions.DEFAULT); + } + + @Test + public void shouldGetHomesteadBlockNumber() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("homesteadBlock", 1000)); + assertThat(config.getHomesteadBlockNumber()).hasValue(1000); + } + + @Test + public void shouldGetDaoForkBlockNumber() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("daoForkBlock", 1000)); + assertThat(config.getDaoForkBlock()).hasValue(1000); + } + + @Test + public void shouldGetTangerineWhistleBlockNumber() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("eip150Block", 1000)); + assertThat(config.getTangerineWhistleBlockNumber()).hasValue(1000); + } + + @Test + public void shouldGetSpuriousDragonBlockNumber() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("eip158Block", 1000)); + assertThat(config.getSpuriousDragonBlockNumber()).hasValue(1000); + } + + @Test + public void shouldGetByzantiumBlockNumber() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("byzantiumBlock", 1000)); + assertThat(config.getByzantiumBlockNumber()).hasValue(1000); + } + + @Test + public void shouldGetConstantinopleBlockNumber() { + final GenesisConfigOptions config = + fromConfigOptions(singletonMap("constantinopleBlock", 1000)); + assertThat(config.getConstantinopleBlockNumber()).hasValue(1000); + } + + @Test + public void shouldNotReturnEmptyOptionalWhenBlockNumberNotSpecified() { + final GenesisConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getHomesteadBlockNumber()).isEmpty(); + assertThat(config.getDaoForkBlock()).isEmpty(); + assertThat(config.getTangerineWhistleBlockNumber()).isEmpty(); + assertThat(config.getSpuriousDragonBlockNumber()).isEmpty(); + assertThat(config.getByzantiumBlockNumber()).isEmpty(); + assertThat(config.getConstantinopleBlockNumber()).isEmpty(); + } + + @Test + public void shouldGetChainIdWhenSpecified() { + final GenesisConfigOptions config = fromConfigOptions(singletonMap("chainId", 32)); + assertThat(config.getChainId()).hasValue(32); + } + + @Test + public void shouldSupportEmptyGenesisConfig() { + final GenesisConfigOptions config = GenesisConfigOptions.fromGenesisConfig("{}"); + assertThat(config.isEthHash()).isFalse(); + assertThat(config.isIbft()).isFalse(); + assertThat(config.isClique()).isFalse(); + assertThat(config.getHomesteadBlockNumber()).isEmpty(); + } + + private GenesisConfigOptions fromConfigOptions(final Map options) { + return GenesisConfigOptions.fromGenesisConfig( + new JsonObject(Collections.singletonMap("config", options))); + } +} diff --git a/config/src/test/java/tech/pegasys/pantheon/config/IbftConfigOptionsTest.java b/config/src/test/java/tech/pegasys/pantheon/config/IbftConfigOptionsTest.java new file mode 100644 index 0000000000..048f3ba0cf --- /dev/null +++ b/config/src/test/java/tech/pegasys/pantheon/config/IbftConfigOptionsTest.java @@ -0,0 +1,88 @@ +/* + * 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 static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; + +import io.vertx.core.json.JsonObject; +import org.junit.Test; + +public class IbftConfigOptionsTest { + + private static final int EXPECTED_DEFAULT_EPOCH_LENGTH = 30_000; + private static final int EXPECTED_DEFAULT_BLOCK_PERIOD = 1; + private static final int EXPECTED_DEFAULT_REQUEST_TIMEOUT = 10_000; + + @Test + public void shouldGetEpochLengthFromConfig() { + final IbftConfigOptions config = fromConfigOptions(singletonMap("epochLength", 10_000)); + assertThat(config.getEpochLength()).isEqualTo(10_000); + } + + @Test + public void shouldFallbackToDefaultEpochLength() { + final IbftConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getEpochLength()).isEqualTo(EXPECTED_DEFAULT_EPOCH_LENGTH); + } + + @Test + public void shouldGetDefaultEpochLengthFromDefaultConfig() { + assertThat(IbftConfigOptions.DEFAULT.getEpochLength()).isEqualTo(EXPECTED_DEFAULT_EPOCH_LENGTH); + } + + @Test + public void shouldGetBlockPeriodFromConfig() { + final IbftConfigOptions config = fromConfigOptions(singletonMap("blockPeriodSeconds", 5)); + assertThat(config.getBlockPeriodSeconds()).isEqualTo(5); + } + + @Test + public void shouldFallbackToDefaultBlockPeriod() { + final IbftConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getBlockPeriodSeconds()).isEqualTo(EXPECTED_DEFAULT_BLOCK_PERIOD); + } + + @Test + public void shouldGetDefaultBlockPeriodFromDefaultConfig() { + assertThat(IbftConfigOptions.DEFAULT.getBlockPeriodSeconds()) + .isEqualTo(EXPECTED_DEFAULT_BLOCK_PERIOD); + } + + @Test + public void shouldGetRequestTimeoutFromConfig() { + final IbftConfigOptions config = fromConfigOptions(singletonMap("requestTimeout", 5)); + assertThat(config.getRequestTimeoutMillis()).isEqualTo(5); + } + + @Test + public void shouldFallbackToDefaultRequestTimeout() { + final IbftConfigOptions config = fromConfigOptions(emptyMap()); + assertThat(config.getRequestTimeoutMillis()).isEqualTo(EXPECTED_DEFAULT_REQUEST_TIMEOUT); + } + + @Test + public void shouldGetDefaultRequestTimeoutFromDefaultConfig() { + assertThat(IbftConfigOptions.DEFAULT.getRequestTimeoutMillis()) + .isEqualTo(EXPECTED_DEFAULT_REQUEST_TIMEOUT); + } + + private IbftConfigOptions fromConfigOptions(final Map ibftConfigOptions) { + return GenesisConfigOptions.fromGenesisConfig( + new JsonObject(singletonMap("config", singletonMap("ibft", ibftConfigOptions)))) + .getIbftConfigOptions(); + } +} diff --git a/consensus/clique/build.gradle b/consensus/clique/build.gradle index 050915cc48..a0da8e6333 100644 --- a/consensus/clique/build.gradle +++ b/consensus/clique/build.gradle @@ -24,6 +24,7 @@ jar { repositories { mavenCentral() } dependencies { + implementation project(':config') implementation project(':crypto') implementation project(':ethereum:core') implementation project(':ethereum:blockcreation') 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 014bde4b5f..5950d68e55 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,34 +12,26 @@ */ package tech.pegasys.pantheon.consensus.clique; +import tech.pegasys.pantheon.config.CliqueConfigOptions; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import java.util.Optional; - -import io.vertx.core.json.JsonObject; - /** Defines the protocol behaviours for a blockchain using Clique. */ public class CliqueProtocolSchedule extends MutableProtocolSchedule { - private static final long DEFAULT_EPOCH_LENGTH = 30_000; - private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1; private static final int DEFAULT_CHAIN_ID = 4; public static ProtocolSchedule create( - final JsonObject config, final KeyPair nodeKeys) { + final GenesisConfigOptions config, final KeyPair nodeKeys) { // Get Config Data - final Optional cliqueConfig = Optional.ofNullable(config.getJsonObject("clique")); - final long epochLength = - cliqueConfig.map(cc -> cc.getLong("epochLength")).orElse(DEFAULT_EPOCH_LENGTH); - final long blockPeriod = - cliqueConfig - .map(cc -> cc.getInteger("blockPeriodSeconds")) - .orElse(DEFAULT_BLOCK_PERIOD_SECONDS); - final int chainId = config.getInteger("chainId", DEFAULT_CHAIN_ID); + 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 CliqueProtocolSchedule(); @@ -54,25 +46,20 @@ public class CliqueProtocolSchedule extends MutableProtocolSchedule 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())); return 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 214f2e8a52..6c1953cc29 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 @@ -14,11 +14,11 @@ package tech.pegasys.pantheon.consensus.clique; import static org.assertj.core.api.Java6Assertions.assertThat; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; -import io.vertx.core.json.JsonObject; import org.junit.Test; public class CliqueProtocolScheduleTest { @@ -26,17 +26,18 @@ public class CliqueProtocolScheduleTest { @Test public void protocolSpecsAreCreatedAtBlockDefinedInJson() { final String jsonInput = - "{\"chainId\": 4,\n" + "{\"config\": " + + "{\"chainId\": 4,\n" + "\"homesteadBlock\": 1,\n" + "\"eip150Block\": 2,\n" + "\"eip155Block\": 3,\n" + "\"eip158Block\": 3,\n" - + "\"byzantiumBlock\": 1035301}"; - - final JsonObject jsonObject = new JsonObject(jsonInput); + + "\"byzantiumBlock\": 1035301}" + + "}"; + final GenesisConfigOptions config = GenesisConfigOptions.fromGenesisConfig(jsonInput); final ProtocolSchedule protocolSchedule = - CliqueProtocolSchedule.create(jsonObject, KeyPair.generate()); + CliqueProtocolSchedule.create(config, KeyPair.generate()); final ProtocolSpec homesteadSpec = protocolSchedule.getByBlockNumber(1); final ProtocolSpec tangerineWhistleSpec = protocolSchedule.getByBlockNumber(2); diff --git a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java index 6f2ba57f16..e2e83ddca0 100644 --- a/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java +++ b/consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java @@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; @@ -47,6 +48,8 @@ import org.junit.Test; public class CliqueMinerExecutorTest { + private static final GenesisConfigOptions GENESIS_CONFIG_OPTIONS = + GenesisConfigOptions.fromGenesisConfig(new JsonObject()); private final KeyPair proposerKeyPair = KeyPair.generate(); private Address localAddress; private final List
validatorList = Lists.newArrayList(); @@ -81,7 +84,7 @@ public class CliqueMinerExecutorTest { new CliqueMinerExecutor( cliqueProtocolContext, Executors.newSingleThreadExecutor(), - CliqueProtocolSchedule.create(new JsonObject(), proposerKeyPair), + CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair), new PendingTransactions(1), proposerKeyPair, new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, wrappedVanityData, false), @@ -111,7 +114,7 @@ public class CliqueMinerExecutorTest { new CliqueMinerExecutor( cliqueProtocolContext, Executors.newSingleThreadExecutor(), - CliqueProtocolSchedule.create(new JsonObject(), proposerKeyPair), + CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair), new PendingTransactions(1), proposerKeyPair, new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, wrappedVanityData, false), diff --git a/consensus/ibftlegacy/build.gradle b/consensus/ibftlegacy/build.gradle index d9b84b4310..5e15e9228a 100644 --- a/consensus/ibftlegacy/build.gradle +++ b/consensus/ibftlegacy/build.gradle @@ -11,6 +11,7 @@ jar { dependencies { implementation project(':consensus:common') implementation project(':consensus:ibft') + implementation project(':config') implementation project(':crypto') implementation project(':ethereum:core') implementation project(':ethereum:blockcreation') 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 6320777123..4f93d56027 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,29 +12,23 @@ */ package tech.pegasys.pantheon.consensus.ibftlegacy; +import tech.pegasys.pantheon.config.GenesisConfigOptions; +import tech.pegasys.pantheon.config.IbftConfigOptions; import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; -import java.util.Optional; - -import io.vertx.core.json.JsonObject; - /** Defines the protocol behaviours for a blockchain using IBFT. */ public class IbftProtocolSchedule { - private static final long DEFAULT_EPOCH_LENGTH = 30_000; - private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1; + private static final int DEFAULT_CHAIN_ID = 1; - public static ProtocolSchedule create(final JsonObject config) { - final long spuriousDragonBlock = config.getLong("spuriousDragonBlock", 0L); - final Optional ibftConfig = Optional.ofNullable(config.getJsonObject("ibft")); - final int chainId = config.getInteger("chainId", 1); - final long epochLength = getEpochLength(ibftConfig); - final long blockPeriod = - ibftConfig - .map(iC -> iC.getInteger("blockPeriodSeconds")) - .orElse(DEFAULT_BLOCK_PERIOD_SECONDS); + 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 MutableProtocolSchedule protocolSchedule = new MutableProtocolSchedule<>(); protocolSchedule.putMilestone( @@ -42,8 +36,4 @@ public class IbftProtocolSchedule { IbftProtocolSpecs.spuriousDragon(blockPeriod, epochLength, chainId, protocolSchedule)); return protocolSchedule; } - - public static long getEpochLength(final Optional ibftConfig) { - return ibftConfig.map(conf -> conf.getLong("epochLength")).orElse(DEFAULT_EPOCH_LENGTH); - } } diff --git a/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java b/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java index 924f8902cf..1fa99e33c6 100644 --- a/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java +++ b/consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java @@ -18,6 +18,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static tech.pegasys.pantheon.ethereum.core.InMemoryTestFixture.createInMemoryWorldStateArchive; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.ibft.IbftContext; @@ -45,7 +46,6 @@ import java.util.List; import java.util.Optional; import com.google.common.collect.Lists; -import io.vertx.core.json.JsonObject; import org.junit.Test; public class IbftBlockCreatorTest { @@ -77,7 +77,8 @@ public class IbftBlockCreatorTest { final VoteTally voteTally = new VoteTally(initialValidatorList); final ProtocolSchedule protocolSchedule = - IbftProtocolSchedule.create(new JsonObject("{\"spuriousDragonBlock\":0}")); + IbftProtocolSchedule.create( + GenesisConfigOptions.fromGenesisConfig("{\"config\": {\"spuriousDragonBlock\":0}}")); final ProtocolContext protContext = new ProtocolContext<>( blockchain, diff --git a/ethereum/core/build.gradle b/ethereum/core/build.gradle index f316ab5933..1842799870 100644 --- a/ethereum/core/build.gradle +++ b/ethereum/core/build.gradle @@ -22,6 +22,7 @@ jar { } dependencies { + implementation project(':config') implementation project(':crypto') implementation project(':ethereum:rlp') implementation project(':ethereum:trie') diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/GenesisConfig.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/GenesisConfig.java index c7230de9dc..cf981e120a 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/GenesisConfig.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/GenesisConfig.java @@ -12,6 +12,7 @@ */ package tech.pegasys.pantheon.ethereum.chain; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockBody; @@ -75,8 +76,8 @@ public final class GenesisConfig { final JsonObject config = new JsonObject( Resources.toString(Resources.getResource(MAINNET_FILE), StandardCharsets.UTF_8)); - return GenesisConfig.fromConfig( - config, MainnetProtocolSchedule.fromConfig(config.getJsonObject("config"))); + final GenesisConfigOptions configOptions = GenesisConfigOptions.fromGenesisConfig(config); + return GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions)); } catch (final IOException ex) { throw new IllegalStateException(ex); } @@ -125,10 +126,10 @@ public final class GenesisConfig { new Block( buildHeader(definition, calculateGenesisStateHash(genesisAccounts), protocolSchedule), BODY); - - final Map config = - (Map) definition.getOrDefault("config", Collections.emptyMap()); - final int chainId = (int) config.getOrDefault("chainId", 1); + final int chainId = + GenesisConfigOptions.fromGenesisConfig(jsonConfig) + .getChainId() + .orElse(MainnetProtocolSchedule.DEFAULT_CHAIN_ID); return new GenesisConfig<>(block, chainId, protocolSchedule, genesisAccounts); } 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 8500c1b1de..936e7a9a91 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,6 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.mainnet; +import tech.pegasys.pantheon.config.GenesisConfigOptions; + import io.vertx.core.json.JsonObject; /** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */ @@ -92,19 +94,19 @@ public class MainnetProtocolSchedule { * points * @return A configured mainnet protocol schedule */ - public static ProtocolSchedule fromConfig(final JsonObject config) { + public static ProtocolSchedule fromConfig(final GenesisConfigOptions config) { final long homesteadBlockNumber = - config.getLong("homesteadBlock", DEFAULT_HOMESTEAD_BLOCK_NUMBER); - final long daoBlockNumber = config.getLong("daoForkBlock", DEFAULT_DAO_BLOCK_NUMBER); + config.getHomesteadBlockNumber().orElse(DEFAULT_HOMESTEAD_BLOCK_NUMBER); + final long daoBlockNumber = config.getDaoForkBlock().orElse(DEFAULT_DAO_BLOCK_NUMBER); final long tangerineWhistleBlockNumber = - config.getLong("eip150Block", DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER); + config.getTangerineWhistleBlockNumber().orElse(DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER); final long spuriousDragonBlockNumber = - config.getLong("eip158Block", DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER); + config.getSpuriousDragonBlockNumber().orElse(DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER); final long byzantiumBlockNumber = - config.getLong("byzantiumBlock", DEFAULT_BYZANTIUM_BLOCK_NUMBER); + config.getByzantiumBlockNumber().orElse(DEFAULT_BYZANTIUM_BLOCK_NUMBER); final long constantinopleBlockNumber = - config.getLong("constantinopleBlock", DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER); - final int chainId = config.getInteger("chainId", DEFAULT_CHAIN_ID); + config.getConstantinopleBlockNumber().orElse(DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER); + final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID); return create( homesteadBlockNumber, daoBlockNumber, 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 42e20aed27..42d2474bdf 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 @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.mainnet; +import tech.pegasys.pantheon.config.GenesisConfigOptions; + import io.vertx.core.json.JsonObject; import org.assertj.core.api.Assertions; import org.junit.Test; @@ -52,7 +54,8 @@ public class MainnetProtocolScheduleTest { @Test public void shouldReturnDefaultProtocolSpecsWhenEmptyJsonConfigIsUsed() { final JsonObject json = new JsonObject("{}"); - final ProtocolSchedule sched = MainnetProtocolSchedule.fromConfig(json); + final ProtocolSchedule sched = + MainnetProtocolSchedule.fromConfig(GenesisConfigOptions.fromGenesisConfig(json)); 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()) @@ -71,8 +74,9 @@ public class MainnetProtocolScheduleTest { public void createFromConfigWithSettings() { final JsonObject json = new JsonObject( - "{\"homesteadBlock\": 2, \"daoForkBlock\": 3, \"eip150Block\": 14, \"eip158Block\": 15, \"byzantiumBlock\": 16, \"constantinopleBlock\": 18, \"chainId\":1234}"); - final ProtocolSchedule sched = MainnetProtocolSchedule.fromConfig(json); + "{\"config\": {\"homesteadBlock\": 2, \"daoForkBlock\": 3, \"eip150Block\": 14, \"eip158Block\": 15, \"byzantiumBlock\": 16, \"constantinopleBlock\": 18, \"chainId\":1234}}"); + final ProtocolSchedule sched = + MainnetProtocolSchedule.fromConfig(GenesisConfigOptions.fromGenesisConfig(json)); Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockNumber(2).getName()).isEqualTo("Homestead"); Assertions.assertThat(sched.getByBlockNumber(3).getName()).isEqualTo("DaoRecoveryInit"); diff --git a/ethereum/jsonrpc/build.gradle b/ethereum/jsonrpc/build.gradle index 7b030605a1..7d74adfbe9 100644 --- a/ethereum/jsonrpc/build.gradle +++ b/ethereum/jsonrpc/build.gradle @@ -45,6 +45,7 @@ dependencies { testImplementation 'io.vertx:vertx-codegen' testImplementation 'io.vertx:vertx-unit' + integrationTestImplementation project(':config') integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') integrationTestImplementation project(':services:kvstore') diff --git a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java index 371521fa51..8cb5fa702e 100644 --- a/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java +++ b/ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java @@ -12,6 +12,7 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; @@ -25,8 +26,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import io.vertx.core.json.JsonObject; - /** Creates a block chain from a genesis and a blocks files. */ public class BlockchainImporter { @@ -39,7 +38,8 @@ public class BlockchainImporter { private final Block genesisBlock; public BlockchainImporter(final URL blocksUrl, final String genesisJson) throws Exception { - protocolSchedule = MainnetProtocolSchedule.fromConfig(new JsonObject(genesisJson)); + protocolSchedule = + MainnetProtocolSchedule.fromConfig(GenesisConfigOptions.fromGenesisConfig(genesisJson)); blocks = new ArrayList<>(); try (final RawBlockIterator iterator = diff --git a/pantheon/build.gradle b/pantheon/build.gradle index c70ee072d6..ca360dec58 100644 --- a/pantheon/build.gradle +++ b/pantheon/build.gradle @@ -22,6 +22,7 @@ jar { } dependencies { + implementation project(':config') implementation project(':crypto') implementation project(':consensus:common') implementation project(':consensus:clique') diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java index 8a3fba44e2..d0ca5fd834 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java @@ -14,6 +14,7 @@ package tech.pegasys.pantheon.controller; import static org.apache.logging.log4j.LogManager.getLogger; +import tech.pegasys.pantheon.config.CliqueConfigOptions; import tech.pegasys.pantheon.consensus.clique.CliqueContext; import tech.pegasys.pantheon.consensus.clique.CliqueVoteTallyUpdater; import tech.pegasys.pantheon.consensus.clique.VoteTallyCache; @@ -59,7 +60,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import io.vertx.core.json.JsonObject; import org.apache.logging.log4j.Logger; public class CliquePantheonController implements PantheonController { @@ -73,8 +73,6 @@ public class CliquePantheonController implements PantheonController genesisConfig, final SynchronizerConfiguration taintedSyncConfig, final MiningParameters miningParams, - final JsonObject cliqueConfig, + final CliqueConfigOptions cliqueConfig, final int networkId, final KeyPair nodeKeys) throws IOException { - final long blocksPerEpoch = cliqueConfig.getLong("epoch", EPOCH_LENGTH_DEFAULT); - final long secondsBetweenBlocks = - cliqueConfig.getLong("period", SECONDS_BETWEEN_BLOCKS_DEFAULT); + final long blocksPerEpoch = cliqueConfig.getEpochLength(); + final long secondsBetweenBlocks = cliqueConfig.getBlockPeriodSeconds(); final EpochManager epochManger = new EpochManager(blocksPerEpoch); final KeyValueStorage kv = 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 f38a3e943f..bcaebe3645 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java @@ -14,6 +14,7 @@ package tech.pegasys.pantheon.controller; import static org.apache.logging.log4j.LogManager.getLogger; +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; @@ -25,7 +26,6 @@ import tech.pegasys.pantheon.consensus.ibft.IbftStateMachine; import tech.pegasys.pantheon.consensus.ibft.network.IbftNetworkPeers; import tech.pegasys.pantheon.consensus.ibft.protocol.IbftProtocolManager; import tech.pegasys.pantheon.consensus.ibft.protocol.IbftSubProtocol; -import tech.pegasys.pantheon.consensus.ibftlegacy.IbftProtocolSchedule; import tech.pegasys.pantheon.consensus.ibftlegacy.IbftVoteTallyUpdater; import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64Protocol; import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64ProtocolManager; @@ -60,17 +60,14 @@ import tech.pegasys.pantheon.services.kvstore.RocksDbKeyValueStorage; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import io.vertx.core.json.JsonObject; import org.apache.logging.log4j.Logger; public class IbftPantheonController implements PantheonController { - private static final int DEFAULT_ROUND_EXPIRY_MILLISECONDS = 10000; private static final Logger LOG = getLogger(); private final GenesisConfig genesisConfig; private final ProtocolContext context; @@ -112,7 +109,7 @@ public class IbftPantheonController implements PantheonController { final GenesisConfig genesisConfig, final SynchronizerConfiguration taintedSyncConfig, final boolean ottomanTestnetOperation, - final JsonObject ibftConfig, + final IbftConfigOptions ibftConfig, final int networkId, final KeyPair nodeKeys) throws IOException { @@ -132,8 +129,7 @@ public class IbftPantheonController implements PantheonController { final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); genesisConfig.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH)); - final EpochManager epochManager = - new EpochManager(IbftProtocolSchedule.getEpochLength(Optional.of(ibftConfig))); + final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength()); final VoteTally voteTally = new IbftVoteTallyUpdater(epochManager).buildVoteTallyFromBlockchain(blockchain); @@ -176,10 +172,7 @@ public class IbftPantheonController implements PantheonController { final IbftStateMachine ibftStateMachine = new IbftStateMachine(); final IbftProcessor ibftProcessor = - new IbftProcessor( - ibftEventQueue, - ibftConfig.getInteger("requestTimeout", DEFAULT_ROUND_EXPIRY_MILLISECONDS), - ibftStateMachine); + new IbftProcessor(ibftEventQueue, ibftConfig.getRequestTimeoutMillis(), ibftStateMachine); final ExecutorService processorExecutor = Executors.newSingleThreadExecutor(); processorExecutor.submit(ibftProcessor); 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 a61e9b260c..0fc330a9f4 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java @@ -12,6 +12,7 @@ */ package tech.pegasys.pantheon.controller; +import tech.pegasys.pantheon.config.GenesisConfigOptions; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.ibftlegacy.IbftProtocolSchedule; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; @@ -47,31 +48,31 @@ public interface PantheonController extends Closeable { throws IOException { final JsonObject config = new JsonObject(configContents); - final JsonObject configOptions = config.getJsonObject("config"); + final GenesisConfigOptions configOptions = GenesisConfigOptions.fromGenesisConfig(config); - if (configOptions.containsKey("ethash")) { + if (configOptions.isEthHash()) { return MainnetPantheonController.init( pantheonHome, GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions)), syncConfig, miningParameters, nodeKeys); - } else if (configOptions.containsKey("ibft")) { + } else if (configOptions.isIbft()) { return IbftPantheonController.init( pantheonHome, GenesisConfig.fromConfig(config, IbftProtocolSchedule.create(configOptions)), syncConfig, ottomanTestnetOperation, - configOptions.getJsonObject("ibft"), + configOptions.getIbftConfigOptions(), networkId, nodeKeys); - } else if (configOptions.containsKey("clique")) { + } else if (configOptions.isClique()) { return CliquePantheonController.init( pantheonHome, GenesisConfig.fromConfig(config, CliqueProtocolSchedule.create(configOptions, nodeKeys)), syncConfig, miningParameters, - configOptions.getJsonObject("clique"), + configOptions.getCliqueConfigOptions(), networkId, nodeKeys); } else { diff --git a/pantheon/src/test/resources/ibft_genesis.json b/pantheon/src/test/resources/ibft_genesis.json index 7d0824af26..870a49f48e 100644 --- a/pantheon/src/test/resources/ibft_genesis.json +++ b/pantheon/src/test/resources/ibft_genesis.json @@ -1,11 +1,11 @@ { "config": { "chainId": 2017, - "homesteadBlock": 1, - "eip150Block": 2, + "homesteadBlock": 0, + "eip150Block": 0, "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "eip155Block": 3, - "eip158Block": 3, + "eip155Block": 0, + "eip158Block": 0, "ibft": { "epochLength": 30000, diff --git a/settings.gradle b/settings.gradle index 9ed5c6e07f..bf1ef6996c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,6 +18,7 @@ include 'consensus:clique' include 'consensus:common' include 'consensus:ibft' include 'consensus:ibftlegacy' +include 'config' include 'crypto' include 'ethereum:p2p' include 'ethereum:mock-p2p'