From 6d255e9213b54500ee1d978239a627b2363a78d8 Mon Sep 17 00:00:00 2001 From: mbaxter Date: Tue, 13 Aug 2019 16:25:12 -0400 Subject: [PATCH] [PIE-1810] Add read-only blockchain factory method (#1845) Signed-off-by: Adrian Sutton --- .../pantheon/ethereum/ProtocolContext.java | 4 +- ...Blockchain.java => DefaultBlockchain.java} | 48 ++++++- .../ethereum/chain/MutableBlockchain.java | 9 ++ .../core/ExecutionContextTestFixture.java | 4 +- .../core/InMemoryStorageProvider.java | 4 +- ...inTest.java => DefaultBlockchainTest.java} | 123 ++++++++++++++---- .../chain/GenesisBlockMismatchTest.java | 108 --------------- .../ethereum/worldstate/PrunerTest.java | 22 ++-- .../ethereum/retesteth/RetestethContext.java | 13 +- .../retesteth/methods/TestMineBlocks.java | 4 +- 10 files changed, 173 insertions(+), 166 deletions(-) rename ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/{DefaultMutableBlockchain.java => DefaultBlockchain.java} (92%) rename ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/{DefaultMutableBlockchainTest.java => DefaultBlockchainTest.java} (87%) delete mode 100644 ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisBlockMismatchTest.java diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/ProtocolContext.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/ProtocolContext.java index beaaf95bc3..be71d5a327 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/ProtocolContext.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/ProtocolContext.java @@ -14,7 +14,7 @@ package tech.pegasys.pantheon.ethereum; import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage; -import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.chain.DefaultBlockchain; import tech.pegasys.pantheon.ethereum.chain.GenesisState; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; @@ -60,7 +60,7 @@ public class ProtocolContext { storageProvider.createWorldStatePreimageStorage(); final MutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); + DefaultBlockchain.createMutable(genesisState.getBlock(), blockchainStorage, metricsSystem); final WorldStateArchive worldStateArchive = new WorldStateArchive(worldStateStorage, preimageStorage); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchain.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchain.java similarity index 92% rename from ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchain.java rename to ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchain.java index a215c6a358..6c2ce8f6ee 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchain.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchain.java @@ -42,7 +42,7 @@ import java.util.Set; import com.google.common.annotations.VisibleForTesting; -public class DefaultMutableBlockchain implements MutableBlockchain { +public class DefaultBlockchain implements MutableBlockchain { protected final BlockchainStorage blockchainStorage; @@ -53,13 +53,16 @@ public class DefaultMutableBlockchain implements MutableBlockchain { private volatile int chainHeadTransactionCount; private volatile int chainHeadOmmerCount; - public DefaultMutableBlockchain( - final Block genesisBlock, + private DefaultBlockchain( + final Optional genesisBlock, final BlockchainStorage blockchainStorage, final MetricsSystem metricsSystem) { checkNotNull(genesisBlock); + checkNotNull(blockchainStorage); + checkNotNull(metricsSystem); + this.blockchainStorage = blockchainStorage; - this.setGenesis(genesisBlock); + genesisBlock.ifPresent(this::setGenesis); final Hash chainHead = blockchainStorage.getChainHead().get(); chainHeader = blockchainStorage.getBlockHeader(chainHead).get(); @@ -112,6 +115,40 @@ public class DefaultMutableBlockchain implements MutableBlockchain { () -> chainHeadOmmerCount); } + public static MutableBlockchain createMutable( + final Block genesisBlock, + final BlockchainStorage blockchainStorage, + final MetricsSystem metricsSystem) { + checkNotNull(genesisBlock); + return new DefaultBlockchain(Optional.of(genesisBlock), blockchainStorage, metricsSystem); + } + + public static Blockchain create( + final BlockchainStorage blockchainStorage, final MetricsSystem metricsSystem) { + checkArgument( + validateStorageNonEmpty(blockchainStorage), "Cannot create Blockchain from empty storage"); + return new DefaultBlockchain(Optional.empty(), blockchainStorage, metricsSystem); + } + + private static boolean validateStorageNonEmpty(final BlockchainStorage blockchainStorage) { + // Run a few basic checks to make sure data looks available and consistent + final Optional maybeHead = blockchainStorage.getChainHead(); + if (maybeHead.isEmpty()) { + return false; + } + final Optional genesisHash = + blockchainStorage.getBlockHash(BlockHeader.GENESIS_BLOCK_NUMBER); + if (genesisHash.isEmpty()) { + return false; + } + final Optional td = blockchainStorage.getTotalDifficulty(maybeHead.get()); + if (td.isEmpty()) { + return false; + } + + return true; + } + @Override public ChainHead getChainHead() { return new ChainHead(chainHeader.getHash(), totalDifficulty, chainHeader.getNumber()); @@ -359,6 +396,7 @@ public class DefaultMutableBlockchain implements MutableBlockchain { removedTransactions); } + @Override public boolean rewindToBlock(final long blockNumber) { final Optional blockHash = blockchainStorage.getBlockHash(blockNumber); if (blockHash.isEmpty()) { @@ -413,7 +451,7 @@ public class DefaultMutableBlockchain implements MutableBlockchain { return new HashSet<>(blockchainStorage.getForkHeads()); } - protected void setGenesis(final Block genesisBlock) { + private void setGenesis(final Block genesisBlock) { checkArgument( genesisBlock.getHeader().getNumber() == BlockHeader.GENESIS_BLOCK_NUMBER, "Invalid genesis block."); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/MutableBlockchain.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/MutableBlockchain.java index 67fe79672e..d3986fa38c 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/MutableBlockchain.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/MutableBlockchain.java @@ -30,4 +30,13 @@ public interface MutableBlockchain extends Blockchain { * @param receipts The list of receipts associated with this block's transactions. */ void appendBlock(Block block, List receipts); + + /** + * Rolls back the canonical chainhead to the specified block number. + * + * @param blockNumber The block number to roll back to. + * @return {@code true} on success, {@code false} if the canonical chain height is less than + * {@code blockNumber} + */ + boolean rewindToBlock(final long blockNumber); } diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java index 6b7805880f..d4ce8a7456 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java @@ -17,7 +17,7 @@ import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.create import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.ethereum.ProtocolContext; -import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.chain.DefaultBlockchain; import tech.pegasys.pantheon.ethereum.chain.GenesisState; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -49,7 +49,7 @@ public class ExecutionContextTestFixture { this.genesis = genesisState.getBlock(); this.keyValueStorage = keyValueStorage; this.blockchain = - new DefaultMutableBlockchain( + DefaultBlockchain.createMutable( genesis, new KeyValueStoragePrefixedKeyBlockchainStorage( keyValueStorage, new MainnetBlockHeaderFunctions()), diff --git a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java index 5f6b763b1f..09f2b82264 100644 --- a/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java +++ b/ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java @@ -13,7 +13,7 @@ package tech.pegasys.pantheon.ethereum.core; import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage; -import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.chain.DefaultBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; @@ -43,7 +43,7 @@ public class InMemoryStorageProvider implements StorageProvider { public static MutableBlockchain createInMemoryBlockchain( final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) { final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); - return new DefaultMutableBlockchain( + return DefaultBlockchain.createMutable( genesisBlock, new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions), new NoOpMetricsSystem()); diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchainTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchainTest.java similarity index 87% rename from ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchainTest.java rename to ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchainTest.java index 08fd254449..854547a841 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultMutableBlockchainTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchainTest.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.ethereum.chain; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; import tech.pegasys.pantheon.ethereum.core.Block; @@ -39,7 +40,7 @@ import java.util.stream.Collectors; import org.junit.Test; -public class DefaultMutableBlockchainTest { +public class DefaultBlockchainTest { @Test public void initializeNew() { @@ -47,7 +48,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); assertBlockDataIsStored(blockchain, genesisBlock, Collections.emptyList()); assertBlockIsHead(blockchain, genesisBlock); @@ -62,10 +63,10 @@ public class DefaultMutableBlockchainTest { // Write to kv store final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - createBlockchain(kvStore, genesisBlock); + createMutableBlockchain(kvStore, genesisBlock); // Initialize a new blockchain store with kvStore that already contains data - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); assertBlockDataIsStored(blockchain, genesisBlock, Collections.emptyList()); assertBlockIsHead(blockchain, genesisBlock); @@ -73,17 +74,75 @@ public class DefaultMutableBlockchainTest { assertThat(blockchain.getForks()).isEmpty(); } - @Test(expected = IllegalArgumentException.class) + @Test public void initializeExistingWithWrongGenesisBlock() { final BlockDataGenerator gen = new BlockDataGenerator(); // Write to kv store final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - createBlockchain(kvStore, genesisBlock); + createMutableBlockchain(kvStore, genesisBlock); // Initialize a new blockchain store with same kvStore, but different genesis block - createBlockchain(kvStore, gen.genesisBlock()); + assertThatThrownBy(() -> createMutableBlockchain(kvStore, gen.genesisBlock())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining( + "Supplied genesis block does not match stored chain data.\n" + + "Please specify a different data directory with --data-path or specify the original genesis file with --genesis-file."); + } + + @Test + public void initializeReadOnly_withGenesisBlock() { + final BlockDataGenerator gen = new BlockDataGenerator(); + final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); + final Block genesisBlock = gen.genesisBlock(); + + // Write genesis block to storage + createMutableBlockchain(kvStore, genesisBlock); + + // Create read only chain + final Blockchain blockchain = createBlockchain(kvStore); + + assertBlockDataIsStored(blockchain, genesisBlock, Collections.emptyList()); + assertBlockIsHead(blockchain, genesisBlock); + assertTotalDifficultiesAreConsistent(blockchain, genesisBlock); + } + + @Test + public void initializeReadOnly_withSmallChain() { + final BlockDataGenerator gen = new BlockDataGenerator(); + final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); + final List blocks = gen.blockSequence(10); + final List> blockReceipts = new ArrayList<>(blocks.size()); + blockReceipts.add(Collections.emptyList()); + + // Write small chain to storage + final MutableBlockchain mutableBlockchain = createMutableBlockchain(kvStore, blocks.get(0)); + for (int i = 1; i < blocks.size(); i++) { + final Block block = blocks.get(i); + final List receipts = gen.receipts(block); + blockReceipts.add(receipts); + mutableBlockchain.appendBlock(block, receipts); + } + + // Create read only chain + final Blockchain blockchain = createBlockchain(kvStore); + + for (int i = 0; i < blocks.size(); i++) { + assertBlockDataIsStored(blockchain, blocks.get(i), blockReceipts.get(i)); + } + final Block lastBlock = blocks.get(blocks.size() - 1); + assertBlockIsHead(blockchain, lastBlock); + assertTotalDifficultiesAreConsistent(blockchain, lastBlock); + } + + @Test + public void initializeReadOnly_emptyStorage() { + final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); + + assertThatThrownBy(() -> createBlockchain(kvStore)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Cannot create Blockchain from empty storage"); } @Test @@ -92,7 +151,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final BlockOptions options = new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); @@ -111,7 +170,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final BlockOptions options = new BlockOptions().setBlockNumber(1L).setParentHash(Hash.ZERO); final Block newBlock = gen.block(options); @@ -125,7 +184,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final BlockOptions options = new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); @@ -143,7 +202,7 @@ public class DefaultMutableBlockchainTest { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -168,7 +227,7 @@ public class DefaultMutableBlockchainTest { final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -225,7 +284,7 @@ public class DefaultMutableBlockchainTest { final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -323,7 +382,7 @@ public class DefaultMutableBlockchainTest { final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -412,7 +471,7 @@ public class DefaultMutableBlockchainTest { final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -465,7 +524,7 @@ public class DefaultMutableBlockchainTest { final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -503,7 +562,7 @@ public class DefaultMutableBlockchainTest { final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, chain.get(0)); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); } @@ -580,7 +639,7 @@ public class DefaultMutableBlockchainTest { final BlockDataGenerator gen = new BlockDataGenerator(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); assertThat(blockchain.removeObserver(7)).isFalse(); } @@ -591,7 +650,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final long observerId = blockchain.observeBlockAdded((block, chain) -> {}); assertThat(blockchain.observerCount()).isEqualTo(1); @@ -606,7 +665,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); blockchain.observeBlockAdded(null); } @@ -617,7 +676,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final long observerId1 = blockchain.observeBlockAdded((block, chain) -> {}); assertThat(blockchain.observerCount()).isEqualTo(1); @@ -644,7 +703,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final BlockOptions options = new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); @@ -665,7 +724,7 @@ public class DefaultMutableBlockchainTest { final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final Block genesisBlock = gen.genesisBlock(); - final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); + final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock); final BlockOptions options = new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); @@ -734,11 +793,19 @@ public class DefaultMutableBlockchainTest { assertEquals(td, blockchain.getChainHead().getTotalDifficulty()); } - private DefaultMutableBlockchain createBlockchain( + private BlockchainStorage createStorage(final KeyValueStorage kvStore) { + return new KeyValueStoragePrefixedKeyBlockchainStorage( + kvStore, new MainnetBlockHeaderFunctions()); + } + + private DefaultBlockchain createMutableBlockchain( final KeyValueStorage kvStore, final Block genesisBlock) { - return new DefaultMutableBlockchain( - genesisBlock, - new KeyValueStoragePrefixedKeyBlockchainStorage(kvStore, new MainnetBlockHeaderFunctions()), - new NoOpMetricsSystem()); + return (DefaultBlockchain) + DefaultBlockchain.createMutable( + genesisBlock, createStorage(kvStore), new NoOpMetricsSystem()); + } + + private Blockchain createBlockchain(final KeyValueStorage kvStore) { + return DefaultBlockchain.create(createStorage(kvStore), new NoOpMetricsSystem()); } } diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisBlockMismatchTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisBlockMismatchTest.java deleted file mode 100644 index dec49ea10e..0000000000 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisBlockMismatchTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2018 ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package tech.pegasys.pantheon.ethereum.chain; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; - -import tech.pegasys.pantheon.crypto.SecureRandomProvider; -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.MainnetBlockHeaderFunctions; -import tech.pegasys.pantheon.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; -import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; -import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; -import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; -import tech.pegasys.pantheon.util.InvalidConfigurationException; -import tech.pegasys.pantheon.util.bytes.Bytes32; -import tech.pegasys.pantheon.util.bytes.BytesValue; -import tech.pegasys.pantheon.util.uint.UInt256; - -import java.security.SecureRandom; -import java.util.Collections; - -import org.junit.Test; - -public class GenesisBlockMismatchTest { - private static final SecureRandom srand = SecureRandomProvider.publicSecureRandom(); - - private static byte[] bytes(final int len) { - final byte[] bytes = new byte[len]; - srand.nextBytes(bytes); - return bytes; - } - - @Test - public void suppliedGenesisBlockMismatchStoredChainDataException() { - final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); - final 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) - .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) - .buildBlockHeader(); - final BlockBody genesisBody00 = new BlockBody(Collections.emptyList(), Collections.emptyList()); - final Block genesisBlock00 = new Block(genesisHeader00, genesisBody00); - final DefaultMutableBlockchain blockchain00 = - new DefaultMutableBlockchain( - genesisBlock00, - new KeyValueStoragePrefixedKeyBlockchainStorage( - kvStore, new MainnetBlockHeaderFunctions()), - new NoOpMetricsSystem()); - - final 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) - .blockHeaderFunctions(new MainnetBlockHeaderFunctions()) - .buildBlockHeader(); - final BlockBody genesisBody01 = new BlockBody(Collections.emptyList(), Collections.emptyList()); - final 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 specify a different data directory with --data-path or specify the original genesis file with --genesis-file."); - } -} diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/PrunerTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/PrunerTest.java index bdd9d87dc6..44936d79ec 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/PrunerTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/PrunerTest.java @@ -19,7 +19,8 @@ import static org.mockito.Mockito.verify; import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage; -import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.chain.DefaultBlockchain; +import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator.BlockOptions; @@ -56,8 +57,8 @@ public class PrunerTest { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); - final DefaultMutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); + final MutableBlockchain blockchain = + DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 0); pruner.start(); @@ -77,8 +78,8 @@ public class PrunerTest { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); - final DefaultMutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); + final MutableBlockchain blockchain = + DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 1, 2); pruner.start(); @@ -103,8 +104,8 @@ public class PrunerTest { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); - final DefaultMutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); + final MutableBlockchain blockchain = + DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem); // start pruner so it can start handling block added events final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 1); @@ -150,8 +151,8 @@ public class PrunerTest { final BlockchainStorage blockchainStorage = new KeyValueStoragePrefixedKeyBlockchainStorage( new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); - final DefaultMutableBlockchain blockchain = - new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); + final MutableBlockchain blockchain = + DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 0); pruner.start(); @@ -159,8 +160,7 @@ public class PrunerTest { verify(markSweepPruner).cleanup(); } - private Block appendBlockWithParent( - final DefaultMutableBlockchain blockchain, final Block parent) { + private Block appendBlockWithParent(final MutableBlockchain blockchain, final Block parent) { BlockOptions options = new BlockOptions() .setBlockNumber(parent.getHeader().getNumber() + 1) diff --git a/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/RetestethContext.java b/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/RetestethContext.java index 7a7bd916bf..fbd4ce6e82 100644 --- a/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/RetestethContext.java +++ b/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/RetestethContext.java @@ -18,8 +18,9 @@ import tech.pegasys.pantheon.config.JsonGenesisConfigOptions; import tech.pegasys.pantheon.config.JsonUtil; import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.blockcreation.IncrementingNonceGenerator; -import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.chain.DefaultBlockchain; import tech.pegasys.pantheon.ethereum.chain.GenesisState; +import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; @@ -67,7 +68,7 @@ public class RetestethContext { private final ReentrantLock contextLock = new ReentrantLock(); private Address coinbase; - private DefaultMutableBlockchain blockchain; + private MutableBlockchain blockchain; private ProtocolContext protocolContext; private BlockchainQueries blockchainQueries; private ProtocolSchedule protocolSchedule; @@ -181,14 +182,14 @@ public class RetestethContext { return true; } - private static DefaultMutableBlockchain createInMemoryBlockchain(final Block genesisBlock) { + private static MutableBlockchain createInMemoryBlockchain(final Block genesisBlock) { return createInMemoryBlockchain(genesisBlock, new MainnetBlockHeaderFunctions()); } - private static DefaultMutableBlockchain createInMemoryBlockchain( + private static MutableBlockchain createInMemoryBlockchain( final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) { final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); - return new DefaultMutableBlockchain( + return DefaultBlockchain.createMutable( genesisBlock, new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions), new NoOpMetricsSystem()); @@ -238,7 +239,7 @@ public class RetestethContext { return coinbase; } - public DefaultMutableBlockchain getBlockchain() { + public MutableBlockchain getBlockchain() { return blockchain; } diff --git a/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/methods/TestMineBlocks.java b/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/methods/TestMineBlocks.java index 162e27a71b..502f070b03 100644 --- a/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/methods/TestMineBlocks.java +++ b/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/methods/TestMineBlocks.java @@ -14,7 +14,7 @@ package tech.pegasys.pantheon.ethereum.retesteth.methods; import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.blockcreation.EthHashBlockCreator; -import tech.pegasys.pantheon.ethereum.chain.DefaultMutableBlockchain; +import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockImporter; import tech.pegasys.pantheon.ethereum.core.Wei; @@ -61,7 +61,7 @@ public class TestMineBlocks implements JsonRpcMethod { final RetestethClock retesethClock = context.getRetestethClock(); final ProtocolSchedule protocolSchedule = context.getProtocolSchedule(); final ProtocolContext protocolContext = context.getProtocolContext(); - final DefaultMutableBlockchain blockchain = context.getBlockchain(); + final MutableBlockchain blockchain = context.getBlockchain(); final HeaderValidationMode headerValidationMode = context.getHeaderValidationMode(); final EthHashBlockCreator blockCreator = new EthHashBlockCreator(