diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java index 2f34b5aac8..5cad3d740f 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/DefaultMutableBlockchain.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; +import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; import tech.pegasys.pantheon.util.Subscribers; import tech.pegasys.pantheon.util.uint.UInt256; @@ -352,8 +353,10 @@ public class DefaultMutableBlockchain implements MutableBlockchain { throw new IllegalStateException("Blockchain is missing genesis block data."); } if (!genesisHash.get().equals(genesisBlock.getHash())) { - throw new IllegalArgumentException( - "Supplied genesis block does not match stored chain data."); + throw new InvalidConfigurationException( + "Supplied genesis block does not match stored chain data.\n" + + "Please ensure the integrity of the file: \'pantheon/ethereum/core/src/main/resources/mainnet.json\'.\n" + + "To set a custom genesis file employ the runtime option \'--genesis=PATH_TO_FILE\'."); } } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/util/InvalidConfigurationException.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/util/InvalidConfigurationException.java new file mode 100644 index 0000000000..3ed799045a --- /dev/null +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/util/InvalidConfigurationException.java @@ -0,0 +1,19 @@ +/* + * Copyright 2018 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.util; + +public class InvalidConfigurationException extends IllegalArgumentException { + public InvalidConfigurationException(final String message) { + super(message); + } +} diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java new file mode 100644 index 0000000000..b1d81eaff4 --- /dev/null +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/db/GenesisBlockMismatchTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.db; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; +import static sun.security.krb5.Confounder.bytes; + +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.Block; +import tech.pegasys.pantheon.ethereum.core.BlockBody; +import tech.pegasys.pantheon.ethereum.core.BlockHeader; +import tech.pegasys.pantheon.ethereum.core.BlockHeaderBuilder; +import tech.pegasys.pantheon.ethereum.core.Hash; +import tech.pegasys.pantheon.ethereum.core.LogsBloomFilter; +import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; +import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; +import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; +import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; +import tech.pegasys.pantheon.util.bytes.Bytes32; +import tech.pegasys.pantheon.util.bytes.BytesValue; +import tech.pegasys.pantheon.util.uint.UInt256; + +import java.util.Collections; + +import org.junit.Test; + +public class GenesisBlockMismatchTest { + + @Test + public void suppliedGenesisBlockMismatchStoredChainDataException() { + KeyValueStorage kvStore = new InMemoryKeyValueStorage(); + BlockHeader genesisHeader00 = + BlockHeaderBuilder.create() + .parentHash(Hash.ZERO) + .ommersHash(Hash.ZERO) + .coinbase(Address.fromHexString("0x0000000000000000000000000000000000000000")) + .stateRoot(Hash.ZERO) + .transactionsRoot(Hash.ZERO) + .receiptsRoot(Hash.ZERO) + .logsBloom(new LogsBloomFilter(BytesValue.of(bytes(LogsBloomFilter.BYTE_SIZE)))) + .difficulty(UInt256.ZERO) + .number(0L) + .gasLimit(1L) + .gasUsed(1L) + .timestamp(0L) + .extraData(Bytes32.wrap(bytes(Bytes32.SIZE))) + .mixHash(Hash.ZERO) + .nonce(0L) + .blockHashFunction(MainnetBlockHashFunction::createHash) + .buildBlockHeader(); + BlockBody genesisBody00 = new BlockBody(Collections.emptyList(), Collections.emptyList()); + Block genesisBlock00 = new Block(genesisHeader00, genesisBody00); + DefaultMutableBlockchain blockchain00 = + new DefaultMutableBlockchain(genesisBlock00, kvStore, MainnetBlockHashFunction::createHash); + + BlockHeader genesisHeader01 = + BlockHeaderBuilder.create() + .parentHash(Hash.ZERO) + .ommersHash(Hash.ZERO) + .coinbase(Address.fromHexString("0x0000000000000000000000000000000000000000")) + .stateRoot(Hash.ZERO) + .transactionsRoot(Hash.ZERO) + .receiptsRoot(Hash.ZERO) + .logsBloom(new LogsBloomFilter(BytesValue.of(bytes(LogsBloomFilter.BYTE_SIZE)))) + .difficulty(UInt256.ZERO) + .number(0L) + .gasLimit(1L) + .gasUsed(1L) + .timestamp(0L) + .extraData(Bytes32.wrap(bytes(Bytes32.SIZE))) + .mixHash(Hash.ZERO) + .nonce(0L) + .blockHashFunction(MainnetBlockHashFunction::createHash) + .buildBlockHeader(); + BlockBody genesisBody01 = new BlockBody(Collections.emptyList(), Collections.emptyList()); + Block genesisBlock01 = new Block(genesisHeader01, genesisBody01); + + assertThatExceptionOfType(InvalidConfigurationException.class) + .isThrownBy(() -> blockchain00.setGenesis(genesisBlock01)) + .withMessageContaining( + "Supplied genesis block does not match stored chain data.\n" + + "Please ensure the integrity of the file: \'pantheon/ethereum/core/src/main/resources/mainnet.json\'.\n" + + "To set a custom genesis file employ the runtime option \'--genesis=PATH_TO_FILE\'."); + } +} diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java index 3b0ba31b00..3e731a821e 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/cli/PantheonCommand.java @@ -31,6 +31,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApi; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcApis; import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration; import tech.pegasys.pantheon.ethereum.p2p.peers.DefaultPeer; +import tech.pegasys.pantheon.ethereum.util.InvalidConfigurationException; import tech.pegasys.pantheon.util.BlockImporter; import tech.pegasys.pantheon.util.BlockchainImporter; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -418,6 +419,8 @@ public class PantheonCommand implements Runnable { syncWithOttoman, new MiningParameters(coinbase, minTransactionGasPrice, extraData, isMiningEnabled), isDevMode); + } catch (final InvalidConfigurationException e) { + throw new ExecutionException(new CommandLine(this), e.getMessage()); } catch (final IOException e) { throw new ExecutionException(new CommandLine(this), "Invalid path", e); } diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java index 2cc0a372c8..5f8312da72 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java @@ -12,7 +12,6 @@ */ package tech.pegasys.pantheon.controller; -import static org.apache.logging.log4j.LogManager.getLogger; import static tech.pegasys.pantheon.controller.KeyPairUtil.loadKeyPair; import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; @@ -52,11 +51,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class MainnetPantheonController implements PantheonController { - private static final Logger LOG = getLogger(); + private static final Logger LOG = LogManager.getLogger(); public static final int MAINNET_NETWORK_ID = 1; private final GenesisConfig genesisConfig;