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.
Adrian Sutton 6 years ago committed by GitHub
parent d650f469f3
commit 824b56f141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 36
      config/build.gradle
  2. 37
      config/src/main/java/tech/pegasys/pantheon/config/CliqueConfigOptions.java
  3. 98
      config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigOptions.java
  4. 42
      config/src/main/java/tech/pegasys/pantheon/config/IbftConfigOptions.java
  5. 70
      config/src/test/java/tech/pegasys/pantheon/config/CliqueConfigOptionsTest.java
  6. 134
      config/src/test/java/tech/pegasys/pantheon/config/GenesisConfigOptionsTest.java
  7. 88
      config/src/test/java/tech/pegasys/pantheon/config/IbftConfigOptionsTest.java
  8. 1
      consensus/clique/build.gradle
  9. 55
      consensus/clique/src/main/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolSchedule.java
  10. 13
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/CliqueProtocolScheduleTest.java
  11. 7
      consensus/clique/src/test/java/tech/pegasys/pantheon/consensus/clique/blockcreation/CliqueMinerExecutorTest.java
  12. 1
      consensus/ibftlegacy/build.gradle
  13. 28
      consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/IbftProtocolSchedule.java
  14. 5
      consensus/ibftlegacy/src/test/java/tech/pegasys/pantheon/consensus/ibftlegacy/blockcreation/IbftBlockCreatorTest.java
  15. 1
      ethereum/core/build.gradle
  16. 13
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/GenesisConfig.java
  17. 18
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolSchedule.java
  18. 10
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetProtocolScheduleTest.java
  19. 1
      ethereum/jsonrpc/build.gradle
  20. 6
      ethereum/jsonrpc/src/integration-test/java/tech/pegasys/pantheon/ethereum/jsonrpc/BlockchainImporter.java
  21. 1
      pantheon/build.gradle
  22. 11
      pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java
  23. 15
      pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java
  24. 13
      pantheon/src/main/java/tech/pegasys/pantheon/controller/PantheonController.java
  25. 8
      pantheon/src/test/resources/ibft_genesis.json
  26. 1
      settings.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'
}

@ -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);
}
}

@ -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();
}
}

@ -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);
}
}

@ -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<String, Object> cliqueConfigOptions) {
return GenesisConfigOptions.fromGenesisConfig(
new JsonObject(singletonMap("config", singletonMap("clique", cliqueConfigOptions))))
.getCliqueConfigOptions();
}
}

@ -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<String, Object> options) {
return GenesisConfigOptions.fromGenesisConfig(
new JsonObject(Collections.singletonMap("config", options)));
}
}

@ -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<String, Object> ibftConfigOptions) {
return GenesisConfigOptions.fromGenesisConfig(
new JsonObject(singletonMap("config", singletonMap("ibft", ibftConfigOptions))))
.getIbftConfigOptions();
}
}

@ -24,6 +24,7 @@ jar {
repositories { mavenCentral() } repositories { mavenCentral() }
dependencies { dependencies {
implementation project(':config')
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation') implementation project(':ethereum:blockcreation')

@ -12,34 +12,26 @@
*/ */
package tech.pegasys.pantheon.consensus.clique; 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.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Util; import tech.pegasys.pantheon.ethereum.core.Util;
import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; 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. */ /** Defines the protocol behaviours for a blockchain using Clique. */
public class CliqueProtocolSchedule extends MutableProtocolSchedule<CliqueContext> { public class CliqueProtocolSchedule extends MutableProtocolSchedule<CliqueContext> {
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; private static final int DEFAULT_CHAIN_ID = 4;
public static ProtocolSchedule<CliqueContext> create( public static ProtocolSchedule<CliqueContext> create(
final JsonObject config, final KeyPair nodeKeys) { final GenesisConfigOptions config, final KeyPair nodeKeys) {
// Get Config Data // Get Config Data
final Optional<JsonObject> cliqueConfig = Optional.ofNullable(config.getJsonObject("clique")); final CliqueConfigOptions cliqueConfig = config.getCliqueConfigOptions();
final long epochLength = final long epochLength = cliqueConfig.getEpochLength();
cliqueConfig.map(cc -> cc.getLong("epochLength")).orElse(DEFAULT_EPOCH_LENGTH); final long blockPeriod = cliqueConfig.getBlockPeriodSeconds();
final long blockPeriod = final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID);
cliqueConfig
.map(cc -> cc.getInteger("blockPeriodSeconds"))
.orElse(DEFAULT_BLOCK_PERIOD_SECONDS);
final int chainId = config.getInteger("chainId", DEFAULT_CHAIN_ID);
final MutableProtocolSchedule<CliqueContext> protocolSchedule = new CliqueProtocolSchedule(); final MutableProtocolSchedule<CliqueContext> protocolSchedule = new CliqueProtocolSchedule();
@ -54,25 +46,20 @@ public class CliqueProtocolSchedule extends MutableProtocolSchedule<CliqueContex
protocolSchedule.putMilestone(0, specs.frontier()); protocolSchedule.putMilestone(0, specs.frontier());
final Long homesteadBlockNumber = config.getLong("homesteadBlock"); config
if (homesteadBlockNumber != null) { .getHomesteadBlockNumber()
protocolSchedule.putMilestone(homesteadBlockNumber, specs.homestead()); .ifPresent(blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.homestead()));
} config
.getTangerineWhistleBlockNumber()
final Long tangerineWhistleBlockNumber = config.getLong("eip150Block"); .ifPresent(
if (tangerineWhistleBlockNumber != null) { blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.tangerineWhistle()));
protocolSchedule.putMilestone(tangerineWhistleBlockNumber, specs.tangerineWhistle()); config
} .getSpuriousDragonBlockNumber()
.ifPresent(
final Long spuriousDragonBlockNumber = config.getLong("eip158Block"); blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.spuriousDragon()));
if (spuriousDragonBlockNumber != null) { config
protocolSchedule.putMilestone(spuriousDragonBlockNumber, specs.spuriousDragon()); .getByzantiumBlockNumber()
} .ifPresent(blockNumber -> protocolSchedule.putMilestone(blockNumber, specs.byzantium()));
final Long byzantiumBlockNumber = config.getLong("byzantiumBlock");
if (byzantiumBlockNumber != null) {
protocolSchedule.putMilestone(byzantiumBlockNumber, specs.byzantium());
}
return protocolSchedule; return protocolSchedule;
} }

@ -14,11 +14,11 @@ package tech.pegasys.pantheon.consensus.clique;
import static org.assertj.core.api.Java6Assertions.assertThat; 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.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSpec;
import io.vertx.core.json.JsonObject;
import org.junit.Test; import org.junit.Test;
public class CliqueProtocolScheduleTest { public class CliqueProtocolScheduleTest {
@ -26,17 +26,18 @@ public class CliqueProtocolScheduleTest {
@Test @Test
public void protocolSpecsAreCreatedAtBlockDefinedInJson() { public void protocolSpecsAreCreatedAtBlockDefinedInJson() {
final String jsonInput = final String jsonInput =
"{\"chainId\": 4,\n" "{\"config\": "
+ "{\"chainId\": 4,\n"
+ "\"homesteadBlock\": 1,\n" + "\"homesteadBlock\": 1,\n"
+ "\"eip150Block\": 2,\n" + "\"eip150Block\": 2,\n"
+ "\"eip155Block\": 3,\n" + "\"eip155Block\": 3,\n"
+ "\"eip158Block\": 3,\n" + "\"eip158Block\": 3,\n"
+ "\"byzantiumBlock\": 1035301}"; + "\"byzantiumBlock\": 1035301}"
+ "}";
final JsonObject jsonObject = new JsonObject(jsonInput);
final GenesisConfigOptions config = GenesisConfigOptions.fromGenesisConfig(jsonInput);
final ProtocolSchedule<CliqueContext> protocolSchedule = final ProtocolSchedule<CliqueContext> protocolSchedule =
CliqueProtocolSchedule.create(jsonObject, KeyPair.generate()); CliqueProtocolSchedule.create(config, KeyPair.generate());
final ProtocolSpec<CliqueContext> homesteadSpec = protocolSchedule.getByBlockNumber(1); final ProtocolSpec<CliqueContext> homesteadSpec = protocolSchedule.getByBlockNumber(1);
final ProtocolSpec<CliqueContext> tangerineWhistleSpec = protocolSchedule.getByBlockNumber(2); final ProtocolSpec<CliqueContext> tangerineWhistleSpec = protocolSchedule.getByBlockNumber(2);

@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; 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.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueExtraData; import tech.pegasys.pantheon.consensus.clique.CliqueExtraData;
import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule;
@ -47,6 +48,8 @@ import org.junit.Test;
public class CliqueMinerExecutorTest { public class CliqueMinerExecutorTest {
private static final GenesisConfigOptions GENESIS_CONFIG_OPTIONS =
GenesisConfigOptions.fromGenesisConfig(new JsonObject());
private final KeyPair proposerKeyPair = KeyPair.generate(); private final KeyPair proposerKeyPair = KeyPair.generate();
private Address localAddress; private Address localAddress;
private final List<Address> validatorList = Lists.newArrayList(); private final List<Address> validatorList = Lists.newArrayList();
@ -81,7 +84,7 @@ public class CliqueMinerExecutorTest {
new CliqueMinerExecutor( new CliqueMinerExecutor(
cliqueProtocolContext, cliqueProtocolContext,
Executors.newSingleThreadExecutor(), Executors.newSingleThreadExecutor(),
CliqueProtocolSchedule.create(new JsonObject(), proposerKeyPair), CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair),
new PendingTransactions(1), new PendingTransactions(1),
proposerKeyPair, proposerKeyPair,
new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, wrappedVanityData, false), new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, wrappedVanityData, false),
@ -111,7 +114,7 @@ public class CliqueMinerExecutorTest {
new CliqueMinerExecutor( new CliqueMinerExecutor(
cliqueProtocolContext, cliqueProtocolContext,
Executors.newSingleThreadExecutor(), Executors.newSingleThreadExecutor(),
CliqueProtocolSchedule.create(new JsonObject(), proposerKeyPair), CliqueProtocolSchedule.create(GENESIS_CONFIG_OPTIONS, proposerKeyPair),
new PendingTransactions(1), new PendingTransactions(1),
proposerKeyPair, proposerKeyPair,
new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, wrappedVanityData, false), new MiningParameters(AddressHelpers.ofValue(1), Wei.ZERO, wrappedVanityData, false),

@ -11,6 +11,7 @@ jar {
dependencies { dependencies {
implementation project(':consensus:common') implementation project(':consensus:common')
implementation project(':consensus:ibft') implementation project(':consensus:ibft')
implementation project(':config')
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:core') implementation project(':ethereum:core')
implementation project(':ethereum:blockcreation') implementation project(':ethereum:blockcreation')

@ -12,29 +12,23 @@
*/ */
package tech.pegasys.pantheon.consensus.ibftlegacy; 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.consensus.ibft.IbftContext;
import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.MutableProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; 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. */ /** Defines the protocol behaviours for a blockchain using IBFT. */
public class IbftProtocolSchedule { public class IbftProtocolSchedule {
private static final long DEFAULT_EPOCH_LENGTH = 30_000; private static final int DEFAULT_CHAIN_ID = 1;
private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1;
public static ProtocolSchedule<IbftContext> create(final JsonObject config) { public static ProtocolSchedule<IbftContext> create(final GenesisConfigOptions config) {
final long spuriousDragonBlock = config.getLong("spuriousDragonBlock", 0L); final long spuriousDragonBlock = config.getSpuriousDragonBlockNumber().orElse(0);
final Optional<JsonObject> ibftConfig = Optional.ofNullable(config.getJsonObject("ibft")); final IbftConfigOptions ibftConfig = config.getIbftConfigOptions();
final int chainId = config.getInteger("chainId", 1); final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID);
final long epochLength = getEpochLength(ibftConfig); final long epochLength = ibftConfig.getEpochLength();
final long blockPeriod = final long blockPeriod = ibftConfig.getBlockPeriodSeconds();
ibftConfig
.map(iC -> iC.getInteger("blockPeriodSeconds"))
.orElse(DEFAULT_BLOCK_PERIOD_SECONDS);
final MutableProtocolSchedule<IbftContext> protocolSchedule = new MutableProtocolSchedule<>(); final MutableProtocolSchedule<IbftContext> protocolSchedule = new MutableProtocolSchedule<>();
protocolSchedule.putMilestone( protocolSchedule.putMilestone(
@ -42,8 +36,4 @@ public class IbftProtocolSchedule {
IbftProtocolSpecs.spuriousDragon(blockPeriod, epochLength, chainId, protocolSchedule)); IbftProtocolSpecs.spuriousDragon(blockPeriod, epochLength, chainId, protocolSchedule));
return protocolSchedule; return protocolSchedule;
} }
public static long getEpochLength(final Optional<JsonObject> ibftConfig) {
return ibftConfig.map(conf -> conf.getLong("epochLength")).orElse(DEFAULT_EPOCH_LENGTH);
}
} }

@ -18,6 +18,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static tech.pegasys.pantheon.ethereum.core.InMemoryTestFixture.createInMemoryWorldStateArchive; 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.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; import tech.pegasys.pantheon.consensus.common.VoteTally;
import tech.pegasys.pantheon.consensus.ibft.IbftContext; import tech.pegasys.pantheon.consensus.ibft.IbftContext;
@ -45,7 +46,6 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import io.vertx.core.json.JsonObject;
import org.junit.Test; import org.junit.Test;
public class IbftBlockCreatorTest { public class IbftBlockCreatorTest {
@ -77,7 +77,8 @@ public class IbftBlockCreatorTest {
final VoteTally voteTally = new VoteTally(initialValidatorList); final VoteTally voteTally = new VoteTally(initialValidatorList);
final ProtocolSchedule<IbftContext> protocolSchedule = final ProtocolSchedule<IbftContext> protocolSchedule =
IbftProtocolSchedule.create(new JsonObject("{\"spuriousDragonBlock\":0}")); IbftProtocolSchedule.create(
GenesisConfigOptions.fromGenesisConfig("{\"config\": {\"spuriousDragonBlock\":0}}"));
final ProtocolContext<IbftContext> protContext = final ProtocolContext<IbftContext> protContext =
new ProtocolContext<>( new ProtocolContext<>(
blockchain, blockchain,

@ -22,6 +22,7 @@ jar {
} }
dependencies { dependencies {
implementation project(':config')
implementation project(':crypto') implementation project(':crypto')
implementation project(':ethereum:rlp') implementation project(':ethereum:rlp')
implementation project(':ethereum:trie') implementation project(':ethereum:trie')

@ -12,6 +12,7 @@
*/ */
package tech.pegasys.pantheon.ethereum.chain; 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.Address;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockBody; import tech.pegasys.pantheon.ethereum.core.BlockBody;
@ -75,8 +76,8 @@ public final class GenesisConfig<C> {
final JsonObject config = final JsonObject config =
new JsonObject( new JsonObject(
Resources.toString(Resources.getResource(MAINNET_FILE), StandardCharsets.UTF_8)); Resources.toString(Resources.getResource(MAINNET_FILE), StandardCharsets.UTF_8));
return GenesisConfig.fromConfig( final GenesisConfigOptions configOptions = GenesisConfigOptions.fromGenesisConfig(config);
config, MainnetProtocolSchedule.fromConfig(config.getJsonObject("config"))); return GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions));
} catch (final IOException ex) { } catch (final IOException ex) {
throw new IllegalStateException(ex); throw new IllegalStateException(ex);
} }
@ -125,10 +126,10 @@ public final class GenesisConfig<C> {
new Block( new Block(
buildHeader(definition, calculateGenesisStateHash(genesisAccounts), protocolSchedule), buildHeader(definition, calculateGenesisStateHash(genesisAccounts), protocolSchedule),
BODY); BODY);
final int chainId =
final Map<String, Object> config = GenesisConfigOptions.fromGenesisConfig(jsonConfig)
(Map<String, Object>) definition.getOrDefault("config", Collections.emptyMap()); .getChainId()
final int chainId = (int) config.getOrDefault("chainId", 1); .orElse(MainnetProtocolSchedule.DEFAULT_CHAIN_ID);
return new GenesisConfig<>(block, chainId, protocolSchedule, genesisAccounts); return new GenesisConfig<>(block, chainId, protocolSchedule, genesisAccounts);
} }

@ -12,6 +12,8 @@
*/ */
package tech.pegasys.pantheon.ethereum.mainnet; package tech.pegasys.pantheon.ethereum.mainnet;
import tech.pegasys.pantheon.config.GenesisConfigOptions;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
/** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */ /** Provides {@link ProtocolSpec} lookups for mainnet hard forks. */
@ -92,19 +94,19 @@ public class MainnetProtocolSchedule {
* points * points
* @return A configured mainnet protocol schedule * @return A configured mainnet protocol schedule
*/ */
public static ProtocolSchedule<Void> fromConfig(final JsonObject config) { public static ProtocolSchedule<Void> fromConfig(final GenesisConfigOptions config) {
final long homesteadBlockNumber = final long homesteadBlockNumber =
config.getLong("homesteadBlock", DEFAULT_HOMESTEAD_BLOCK_NUMBER); config.getHomesteadBlockNumber().orElse(DEFAULT_HOMESTEAD_BLOCK_NUMBER);
final long daoBlockNumber = config.getLong("daoForkBlock", DEFAULT_DAO_BLOCK_NUMBER); final long daoBlockNumber = config.getDaoForkBlock().orElse(DEFAULT_DAO_BLOCK_NUMBER);
final long tangerineWhistleBlockNumber = final long tangerineWhistleBlockNumber =
config.getLong("eip150Block", DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER); config.getTangerineWhistleBlockNumber().orElse(DEFAULT_TANGERINE_WHISTLE_BLOCK_NUMBER);
final long spuriousDragonBlockNumber = final long spuriousDragonBlockNumber =
config.getLong("eip158Block", DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER); config.getSpuriousDragonBlockNumber().orElse(DEFAULT_SPURIOUS_DRAGON_BLOCK_NUMBER);
final long byzantiumBlockNumber = final long byzantiumBlockNumber =
config.getLong("byzantiumBlock", DEFAULT_BYZANTIUM_BLOCK_NUMBER); config.getByzantiumBlockNumber().orElse(DEFAULT_BYZANTIUM_BLOCK_NUMBER);
final long constantinopleBlockNumber = final long constantinopleBlockNumber =
config.getLong("constantinopleBlock", DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER); config.getConstantinopleBlockNumber().orElse(DEFAULT_CONSTANTINOPLE_BLOCK_NUMBER);
final int chainId = config.getInteger("chainId", DEFAULT_CHAIN_ID); final int chainId = config.getChainId().orElse(DEFAULT_CHAIN_ID);
return create( return create(
homesteadBlockNumber, homesteadBlockNumber,
daoBlockNumber, daoBlockNumber,

@ -12,6 +12,8 @@
*/ */
package tech.pegasys.pantheon.ethereum.mainnet; package tech.pegasys.pantheon.ethereum.mainnet;
import tech.pegasys.pantheon.config.GenesisConfigOptions;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.junit.Test; import org.junit.Test;
@ -52,7 +54,8 @@ public class MainnetProtocolScheduleTest {
@Test @Test
public void shouldReturnDefaultProtocolSpecsWhenEmptyJsonConfigIsUsed() { public void shouldReturnDefaultProtocolSpecsWhenEmptyJsonConfigIsUsed() {
final JsonObject json = new JsonObject("{}"); final JsonObject json = new JsonObject("{}");
final ProtocolSchedule<Void> sched = MainnetProtocolSchedule.fromConfig(json); final ProtocolSchedule<Void> sched =
MainnetProtocolSchedule.fromConfig(GenesisConfigOptions.fromGenesisConfig(json));
Assertions.assertThat(sched.getByBlockNumber(1L).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockNumber(1L).getName()).isEqualTo("Frontier");
Assertions.assertThat(sched.getByBlockNumber(1_150_000L).getName()).isEqualTo("Homestead"); Assertions.assertThat(sched.getByBlockNumber(1_150_000L).getName()).isEqualTo("Homestead");
Assertions.assertThat(sched.getByBlockNumber(1_920_000L).getName()) Assertions.assertThat(sched.getByBlockNumber(1_920_000L).getName())
@ -71,8 +74,9 @@ public class MainnetProtocolScheduleTest {
public void createFromConfigWithSettings() { public void createFromConfigWithSettings() {
final JsonObject json = final JsonObject json =
new JsonObject( new JsonObject(
"{\"homesteadBlock\": 2, \"daoForkBlock\": 3, \"eip150Block\": 14, \"eip158Block\": 15, \"byzantiumBlock\": 16, \"constantinopleBlock\": 18, \"chainId\":1234}"); "{\"config\": {\"homesteadBlock\": 2, \"daoForkBlock\": 3, \"eip150Block\": 14, \"eip158Block\": 15, \"byzantiumBlock\": 16, \"constantinopleBlock\": 18, \"chainId\":1234}}");
final ProtocolSchedule<Void> sched = MainnetProtocolSchedule.fromConfig(json); final ProtocolSchedule<Void> sched =
MainnetProtocolSchedule.fromConfig(GenesisConfigOptions.fromGenesisConfig(json));
Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("Frontier"); Assertions.assertThat(sched.getByBlockNumber(1).getName()).isEqualTo("Frontier");
Assertions.assertThat(sched.getByBlockNumber(2).getName()).isEqualTo("Homestead"); Assertions.assertThat(sched.getByBlockNumber(2).getName()).isEqualTo("Homestead");
Assertions.assertThat(sched.getByBlockNumber(3).getName()).isEqualTo("DaoRecoveryInit"); Assertions.assertThat(sched.getByBlockNumber(3).getName()).isEqualTo("DaoRecoveryInit");

@ -45,6 +45,7 @@ dependencies {
testImplementation 'io.vertx:vertx-codegen' testImplementation 'io.vertx:vertx-codegen'
testImplementation 'io.vertx:vertx-unit' testImplementation 'io.vertx:vertx-unit'
integrationTestImplementation project(':config')
integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts') integrationTestImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
integrationTestImplementation project(':services:kvstore') integrationTestImplementation project(':services:kvstore')

@ -12,6 +12,7 @@
*/ */
package tech.pegasys.pantheon.ethereum.jsonrpc; package tech.pegasys.pantheon.ethereum.jsonrpc;
import tech.pegasys.pantheon.config.GenesisConfigOptions;
import tech.pegasys.pantheon.ethereum.chain.GenesisConfig; import tech.pegasys.pantheon.ethereum.chain.GenesisConfig;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
@ -25,8 +26,6 @@ import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import io.vertx.core.json.JsonObject;
/** Creates a block chain from a genesis and a blocks files. */ /** Creates a block chain from a genesis and a blocks files. */
public class BlockchainImporter { public class BlockchainImporter {
@ -39,7 +38,8 @@ public class BlockchainImporter {
private final Block genesisBlock; private final Block genesisBlock;
public BlockchainImporter(final URL blocksUrl, final String genesisJson) throws Exception { 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<>(); blocks = new ArrayList<>();
try (final RawBlockIterator iterator = try (final RawBlockIterator iterator =

@ -22,6 +22,7 @@ jar {
} }
dependencies { dependencies {
implementation project(':config')
implementation project(':crypto') implementation project(':crypto')
implementation project(':consensus:common') implementation project(':consensus:common')
implementation project(':consensus:clique') implementation project(':consensus:clique')

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.controller;
import static org.apache.logging.log4j.LogManager.getLogger; 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.CliqueContext;
import tech.pegasys.pantheon.consensus.clique.CliqueVoteTallyUpdater; import tech.pegasys.pantheon.consensus.clique.CliqueVoteTallyUpdater;
import tech.pegasys.pantheon.consensus.clique.VoteTallyCache; 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.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
public class CliquePantheonController implements PantheonController<CliqueContext> { public class CliquePantheonController implements PantheonController<CliqueContext> {
@ -73,8 +73,6 @@ public class CliquePantheonController implements PantheonController<CliqueContex
private final TransactionPool transactionPool; private final TransactionPool transactionPool;
private final Runnable closer; private final Runnable closer;
private static final long EPOCH_LENGTH_DEFAULT = 30_000L;
private static final long SECONDS_BETWEEN_BLOCKS_DEFAULT = 15L;
private final MiningCoordinator miningCoordinator; private final MiningCoordinator miningCoordinator;
CliquePantheonController( CliquePantheonController(
@ -102,13 +100,12 @@ public class CliquePantheonController implements PantheonController<CliqueContex
final GenesisConfig<CliqueContext> genesisConfig, final GenesisConfig<CliqueContext> genesisConfig,
final SynchronizerConfiguration taintedSyncConfig, final SynchronizerConfiguration taintedSyncConfig,
final MiningParameters miningParams, final MiningParameters miningParams,
final JsonObject cliqueConfig, final CliqueConfigOptions cliqueConfig,
final int networkId, final int networkId,
final KeyPair nodeKeys) final KeyPair nodeKeys)
throws IOException { throws IOException {
final long blocksPerEpoch = cliqueConfig.getLong("epoch", EPOCH_LENGTH_DEFAULT); final long blocksPerEpoch = cliqueConfig.getEpochLength();
final long secondsBetweenBlocks = final long secondsBetweenBlocks = cliqueConfig.getBlockPeriodSeconds();
cliqueConfig.getLong("period", SECONDS_BETWEEN_BLOCKS_DEFAULT);
final EpochManager epochManger = new EpochManager(blocksPerEpoch); final EpochManager epochManger = new EpochManager(blocksPerEpoch);
final KeyValueStorage kv = final KeyValueStorage kv =

@ -14,6 +14,7 @@ package tech.pegasys.pantheon.controller;
import static org.apache.logging.log4j.LogManager.getLogger; 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.EpochManager;
import tech.pegasys.pantheon.consensus.common.VoteProposer; import tech.pegasys.pantheon.consensus.common.VoteProposer;
import tech.pegasys.pantheon.consensus.common.VoteTally; 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.network.IbftNetworkPeers;
import tech.pegasys.pantheon.consensus.ibft.protocol.IbftProtocolManager; import tech.pegasys.pantheon.consensus.ibft.protocol.IbftProtocolManager;
import tech.pegasys.pantheon.consensus.ibft.protocol.IbftSubProtocol; 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.IbftVoteTallyUpdater;
import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64Protocol; import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64Protocol;
import tech.pegasys.pantheon.consensus.ibftlegacy.protocol.Istanbul64ProtocolManager; 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.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
public class IbftPantheonController implements PantheonController<IbftContext> { public class IbftPantheonController implements PantheonController<IbftContext> {
private static final int DEFAULT_ROUND_EXPIRY_MILLISECONDS = 10000;
private static final Logger LOG = getLogger(); private static final Logger LOG = getLogger();
private final GenesisConfig<IbftContext> genesisConfig; private final GenesisConfig<IbftContext> genesisConfig;
private final ProtocolContext<IbftContext> context; private final ProtocolContext<IbftContext> context;
@ -112,7 +109,7 @@ public class IbftPantheonController implements PantheonController<IbftContext> {
final GenesisConfig<IbftContext> genesisConfig, final GenesisConfig<IbftContext> genesisConfig,
final SynchronizerConfiguration taintedSyncConfig, final SynchronizerConfiguration taintedSyncConfig,
final boolean ottomanTestnetOperation, final boolean ottomanTestnetOperation,
final JsonObject ibftConfig, final IbftConfigOptions ibftConfig,
final int networkId, final int networkId,
final KeyPair nodeKeys) final KeyPair nodeKeys)
throws IOException { throws IOException {
@ -132,8 +129,7 @@ public class IbftPantheonController implements PantheonController<IbftContext> {
final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage);
genesisConfig.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH)); genesisConfig.writeStateTo(worldStateArchive.getMutable(Hash.EMPTY_TRIE_HASH));
final EpochManager epochManager = final EpochManager epochManager = new EpochManager(ibftConfig.getEpochLength());
new EpochManager(IbftProtocolSchedule.getEpochLength(Optional.of(ibftConfig)));
final VoteTally voteTally = final VoteTally voteTally =
new IbftVoteTallyUpdater(epochManager).buildVoteTallyFromBlockchain(blockchain); new IbftVoteTallyUpdater(epochManager).buildVoteTallyFromBlockchain(blockchain);
@ -176,10 +172,7 @@ public class IbftPantheonController implements PantheonController<IbftContext> {
final IbftStateMachine ibftStateMachine = new IbftStateMachine(); final IbftStateMachine ibftStateMachine = new IbftStateMachine();
final IbftProcessor ibftProcessor = final IbftProcessor ibftProcessor =
new IbftProcessor( new IbftProcessor(ibftEventQueue, ibftConfig.getRequestTimeoutMillis(), ibftStateMachine);
ibftEventQueue,
ibftConfig.getInteger("requestTimeout", DEFAULT_ROUND_EXPIRY_MILLISECONDS),
ibftStateMachine);
final ExecutorService processorExecutor = Executors.newSingleThreadExecutor(); final ExecutorService processorExecutor = Executors.newSingleThreadExecutor();
processorExecutor.submit(ibftProcessor); processorExecutor.submit(ibftProcessor);

@ -12,6 +12,7 @@
*/ */
package tech.pegasys.pantheon.controller; package tech.pegasys.pantheon.controller;
import tech.pegasys.pantheon.config.GenesisConfigOptions;
import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule; import tech.pegasys.pantheon.consensus.clique.CliqueProtocolSchedule;
import tech.pegasys.pantheon.consensus.ibftlegacy.IbftProtocolSchedule; import tech.pegasys.pantheon.consensus.ibftlegacy.IbftProtocolSchedule;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
@ -47,31 +48,31 @@ public interface PantheonController<C> extends Closeable {
throws IOException { throws IOException {
final JsonObject config = new JsonObject(configContents); 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( return MainnetPantheonController.init(
pantheonHome, pantheonHome,
GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions)), GenesisConfig.fromConfig(config, MainnetProtocolSchedule.fromConfig(configOptions)),
syncConfig, syncConfig,
miningParameters, miningParameters,
nodeKeys); nodeKeys);
} else if (configOptions.containsKey("ibft")) { } else if (configOptions.isIbft()) {
return IbftPantheonController.init( return IbftPantheonController.init(
pantheonHome, pantheonHome,
GenesisConfig.fromConfig(config, IbftProtocolSchedule.create(configOptions)), GenesisConfig.fromConfig(config, IbftProtocolSchedule.create(configOptions)),
syncConfig, syncConfig,
ottomanTestnetOperation, ottomanTestnetOperation,
configOptions.getJsonObject("ibft"), configOptions.getIbftConfigOptions(),
networkId, networkId,
nodeKeys); nodeKeys);
} else if (configOptions.containsKey("clique")) { } else if (configOptions.isClique()) {
return CliquePantheonController.init( return CliquePantheonController.init(
pantheonHome, pantheonHome,
GenesisConfig.fromConfig(config, CliqueProtocolSchedule.create(configOptions, nodeKeys)), GenesisConfig.fromConfig(config, CliqueProtocolSchedule.create(configOptions, nodeKeys)),
syncConfig, syncConfig,
miningParameters, miningParameters,
configOptions.getJsonObject("clique"), configOptions.getCliqueConfigOptions(),
networkId, networkId,
nodeKeys); nodeKeys);
} else { } else {

@ -1,11 +1,11 @@
{ {
"config": { "config": {
"chainId": 2017, "chainId": 2017,
"homesteadBlock": 1, "homesteadBlock": 0,
"eip150Block": 2, "eip150Block": 0,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 3, "eip155Block": 0,
"eip158Block": 3, "eip158Block": 0,
"ibft": { "ibft": {
"epochLength": 30000, "epochLength": 30000,

@ -18,6 +18,7 @@ include 'consensus:clique'
include 'consensus:common' include 'consensus:common'
include 'consensus:ibft' include 'consensus:ibft'
include 'consensus:ibftlegacy' include 'consensus:ibftlegacy'
include 'config'
include 'crypto' include 'crypto'
include 'ethereum:p2p' include 'ethereum:p2p'
include 'ethereum:mock-p2p' include 'ethereum:mock-p2p'

Loading…
Cancel
Save