[PIE-1810] Add read-only blockchain factory method (#1845)

Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
mbaxter 5 years ago committed by GitHub
parent 9a16021a89
commit 6d255e9213
  1. 4
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/ProtocolContext.java
  2. 48
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchain.java
  3. 9
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/chain/MutableBlockchain.java
  4. 4
      ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/ExecutionContextTestFixture.java
  5. 4
      ethereum/core/src/test-support/java/tech/pegasys/pantheon/ethereum/core/InMemoryStorageProvider.java
  6. 123
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/DefaultBlockchainTest.java
  7. 108
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/chain/GenesisBlockMismatchTest.java
  8. 22
      ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/PrunerTest.java
  9. 13
      ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/RetestethContext.java
  10. 4
      ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/methods/TestMineBlocks.java

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.ethereum;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage; 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.GenesisState;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
@ -60,7 +60,7 @@ public class ProtocolContext<C> {
storageProvider.createWorldStatePreimageStorage(); storageProvider.createWorldStatePreimageStorage();
final MutableBlockchain blockchain = final MutableBlockchain blockchain =
new DefaultMutableBlockchain(genesisState.getBlock(), blockchainStorage, metricsSystem); DefaultBlockchain.createMutable(genesisState.getBlock(), blockchainStorage, metricsSystem);
final WorldStateArchive worldStateArchive = final WorldStateArchive worldStateArchive =
new WorldStateArchive(worldStateStorage, preimageStorage); new WorldStateArchive(worldStateStorage, preimageStorage);

@ -42,7 +42,7 @@ import java.util.Set;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
public class DefaultMutableBlockchain implements MutableBlockchain { public class DefaultBlockchain implements MutableBlockchain {
protected final BlockchainStorage blockchainStorage; protected final BlockchainStorage blockchainStorage;
@ -53,13 +53,16 @@ public class DefaultMutableBlockchain implements MutableBlockchain {
private volatile int chainHeadTransactionCount; private volatile int chainHeadTransactionCount;
private volatile int chainHeadOmmerCount; private volatile int chainHeadOmmerCount;
public DefaultMutableBlockchain( private DefaultBlockchain(
final Block genesisBlock, final Optional<Block> genesisBlock,
final BlockchainStorage blockchainStorage, final BlockchainStorage blockchainStorage,
final MetricsSystem metricsSystem) { final MetricsSystem metricsSystem) {
checkNotNull(genesisBlock); checkNotNull(genesisBlock);
checkNotNull(blockchainStorage);
checkNotNull(metricsSystem);
this.blockchainStorage = blockchainStorage; this.blockchainStorage = blockchainStorage;
this.setGenesis(genesisBlock); genesisBlock.ifPresent(this::setGenesis);
final Hash chainHead = blockchainStorage.getChainHead().get(); final Hash chainHead = blockchainStorage.getChainHead().get();
chainHeader = blockchainStorage.getBlockHeader(chainHead).get(); chainHeader = blockchainStorage.getBlockHeader(chainHead).get();
@ -112,6 +115,40 @@ public class DefaultMutableBlockchain implements MutableBlockchain {
() -> chainHeadOmmerCount); () -> 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<Hash> maybeHead = blockchainStorage.getChainHead();
if (maybeHead.isEmpty()) {
return false;
}
final Optional<Hash> genesisHash =
blockchainStorage.getBlockHash(BlockHeader.GENESIS_BLOCK_NUMBER);
if (genesisHash.isEmpty()) {
return false;
}
final Optional<UInt256> td = blockchainStorage.getTotalDifficulty(maybeHead.get());
if (td.isEmpty()) {
return false;
}
return true;
}
@Override @Override
public ChainHead getChainHead() { public ChainHead getChainHead() {
return new ChainHead(chainHeader.getHash(), totalDifficulty, chainHeader.getNumber()); return new ChainHead(chainHeader.getHash(), totalDifficulty, chainHeader.getNumber());
@ -359,6 +396,7 @@ public class DefaultMutableBlockchain implements MutableBlockchain {
removedTransactions); removedTransactions);
} }
@Override
public boolean rewindToBlock(final long blockNumber) { public boolean rewindToBlock(final long blockNumber) {
final Optional<Hash> blockHash = blockchainStorage.getBlockHash(blockNumber); final Optional<Hash> blockHash = blockchainStorage.getBlockHash(blockNumber);
if (blockHash.isEmpty()) { if (blockHash.isEmpty()) {
@ -413,7 +451,7 @@ public class DefaultMutableBlockchain implements MutableBlockchain {
return new HashSet<>(blockchainStorage.getForkHeads()); return new HashSet<>(blockchainStorage.getForkHeads());
} }
protected void setGenesis(final Block genesisBlock) { private void setGenesis(final Block genesisBlock) {
checkArgument( checkArgument(
genesisBlock.getHeader().getNumber() == BlockHeader.GENESIS_BLOCK_NUMBER, genesisBlock.getHeader().getNumber() == BlockHeader.GENESIS_BLOCK_NUMBER,
"Invalid genesis block."); "Invalid genesis block.");

@ -30,4 +30,13 @@ public interface MutableBlockchain extends Blockchain {
* @param receipts The list of receipts associated with this block's transactions. * @param receipts The list of receipts associated with this block's transactions.
*/ */
void appendBlock(Block block, List<TransactionReceipt> receipts); void appendBlock(Block block, List<TransactionReceipt> 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);
} }

@ -17,7 +17,7 @@ import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.create
import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.config.GenesisConfigFile;
import tech.pegasys.pantheon.config.StubGenesisConfigOptions; import tech.pegasys.pantheon.config.StubGenesisConfigOptions;
import tech.pegasys.pantheon.ethereum.ProtocolContext; 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.GenesisState;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions;
@ -49,7 +49,7 @@ public class ExecutionContextTestFixture {
this.genesis = genesisState.getBlock(); this.genesis = genesisState.getBlock();
this.keyValueStorage = keyValueStorage; this.keyValueStorage = keyValueStorage;
this.blockchain = this.blockchain =
new DefaultMutableBlockchain( DefaultBlockchain.createMutable(
genesis, genesis,
new KeyValueStoragePrefixedKeyBlockchainStorage( new KeyValueStoragePrefixedKeyBlockchainStorage(
keyValueStorage, new MainnetBlockHeaderFunctions()), keyValueStorage, new MainnetBlockHeaderFunctions()),

@ -13,7 +13,7 @@
package tech.pegasys.pantheon.ethereum.core; package tech.pegasys.pantheon.ethereum.core;
import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage; 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.chain.MutableBlockchain;
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHeaderFunctions;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
@ -43,7 +43,7 @@ public class InMemoryStorageProvider implements StorageProvider {
public static MutableBlockchain createInMemoryBlockchain( public static MutableBlockchain createInMemoryBlockchain(
final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) { final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) {
final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
return new DefaultMutableBlockchain( return DefaultBlockchain.createMutable(
genesisBlock, genesisBlock,
new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions), new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions),
new NoOpMetricsSystem()); new NoOpMetricsSystem());

@ -13,6 +13,7 @@
package tech.pegasys.pantheon.ethereum.chain; package tech.pegasys.pantheon.ethereum.chain;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Block;
@ -39,7 +40,7 @@ import java.util.stream.Collectors;
import org.junit.Test; import org.junit.Test;
public class DefaultMutableBlockchainTest { public class DefaultBlockchainTest {
@Test @Test
public void initializeNew() { public void initializeNew() {
@ -47,7 +48,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
assertBlockDataIsStored(blockchain, genesisBlock, Collections.emptyList()); assertBlockDataIsStored(blockchain, genesisBlock, Collections.emptyList());
assertBlockIsHead(blockchain, genesisBlock); assertBlockIsHead(blockchain, genesisBlock);
@ -62,10 +63,10 @@ public class DefaultMutableBlockchainTest {
// Write to kv store // Write to kv store
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
createBlockchain(kvStore, genesisBlock); createMutableBlockchain(kvStore, genesisBlock);
// Initialize a new blockchain store with kvStore that already contains data // 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()); assertBlockDataIsStored(blockchain, genesisBlock, Collections.emptyList());
assertBlockIsHead(blockchain, genesisBlock); assertBlockIsHead(blockchain, genesisBlock);
@ -73,17 +74,75 @@ public class DefaultMutableBlockchainTest {
assertThat(blockchain.getForks()).isEmpty(); assertThat(blockchain.getForks()).isEmpty();
} }
@Test(expected = IllegalArgumentException.class) @Test
public void initializeExistingWithWrongGenesisBlock() { public void initializeExistingWithWrongGenesisBlock() {
final BlockDataGenerator gen = new BlockDataGenerator(); final BlockDataGenerator gen = new BlockDataGenerator();
// Write to kv store // Write to kv store
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
createBlockchain(kvStore, genesisBlock); createMutableBlockchain(kvStore, genesisBlock);
// Initialize a new blockchain store with same kvStore, but different genesis block // 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<Block> blocks = gen.blockSequence(10);
final List<List<TransactionReceipt>> 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<TransactionReceipt> 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 @Test
@ -92,7 +151,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
final BlockOptions options = final BlockOptions options =
new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash());
@ -111,7 +170,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); 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 BlockOptions options = new BlockOptions().setBlockNumber(1L).setParentHash(Hash.ZERO);
final Block newBlock = gen.block(options); final Block newBlock = gen.block(options);
@ -125,7 +184,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
final BlockOptions options = final BlockOptions options =
new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash());
@ -143,7 +202,7 @@ public class DefaultMutableBlockchainTest {
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -168,7 +227,7 @@ public class DefaultMutableBlockchainTest {
final List<List<TransactionReceipt>> blockReceipts = final List<List<TransactionReceipt>> blockReceipts =
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -225,7 +284,7 @@ public class DefaultMutableBlockchainTest {
final List<List<TransactionReceipt>> blockReceipts = final List<List<TransactionReceipt>> blockReceipts =
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -323,7 +382,7 @@ public class DefaultMutableBlockchainTest {
final List<List<TransactionReceipt>> blockReceipts = final List<List<TransactionReceipt>> blockReceipts =
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -412,7 +471,7 @@ public class DefaultMutableBlockchainTest {
final List<List<TransactionReceipt>> blockReceipts = final List<List<TransactionReceipt>> blockReceipts =
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -465,7 +524,7 @@ public class DefaultMutableBlockchainTest {
final List<List<TransactionReceipt>> blockReceipts = final List<List<TransactionReceipt>> blockReceipts =
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -503,7 +562,7 @@ public class DefaultMutableBlockchainTest {
final List<List<TransactionReceipt>> blockReceipts = final List<List<TransactionReceipt>> blockReceipts =
chain.stream().map(gen::receipts).collect(Collectors.toList()); chain.stream().map(gen::receipts).collect(Collectors.toList());
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); 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++) { for (int i = 1; i < chain.size(); i++) {
blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); blockchain.appendBlock(chain.get(i), blockReceipts.get(i));
} }
@ -580,7 +639,7 @@ public class DefaultMutableBlockchainTest {
final BlockDataGenerator gen = new BlockDataGenerator(); final BlockDataGenerator gen = new BlockDataGenerator();
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
assertThat(blockchain.removeObserver(7)).isFalse(); assertThat(blockchain.removeObserver(7)).isFalse();
} }
@ -591,7 +650,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
final long observerId = blockchain.observeBlockAdded((block, chain) -> {}); final long observerId = blockchain.observeBlockAdded((block, chain) -> {});
assertThat(blockchain.observerCount()).isEqualTo(1); assertThat(blockchain.observerCount()).isEqualTo(1);
@ -606,7 +665,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
blockchain.observeBlockAdded(null); blockchain.observeBlockAdded(null);
} }
@ -617,7 +676,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
final long observerId1 = blockchain.observeBlockAdded((block, chain) -> {}); final long observerId1 = blockchain.observeBlockAdded((block, chain) -> {});
assertThat(blockchain.observerCount()).isEqualTo(1); assertThat(blockchain.observerCount()).isEqualTo(1);
@ -644,7 +703,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
final BlockOptions options = final BlockOptions options =
new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash());
@ -665,7 +724,7 @@ public class DefaultMutableBlockchainTest {
final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final KeyValueStorage kvStore = new InMemoryKeyValueStorage();
final Block genesisBlock = gen.genesisBlock(); final Block genesisBlock = gen.genesisBlock();
final DefaultMutableBlockchain blockchain = createBlockchain(kvStore, genesisBlock); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, genesisBlock);
final BlockOptions options = final BlockOptions options =
new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash()); new BlockOptions().setBlockNumber(1L).setParentHash(genesisBlock.getHash());
@ -734,11 +793,19 @@ public class DefaultMutableBlockchainTest {
assertEquals(td, blockchain.getChainHead().getTotalDifficulty()); 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) { final KeyValueStorage kvStore, final Block genesisBlock) {
return new DefaultMutableBlockchain( return (DefaultBlockchain)
genesisBlock, DefaultBlockchain.createMutable(
new KeyValueStoragePrefixedKeyBlockchainStorage(kvStore, new MainnetBlockHeaderFunctions()), genesisBlock, createStorage(kvStore), new NoOpMetricsSystem());
new NoOpMetricsSystem()); }
private Blockchain createBlockchain(final KeyValueStorage kvStore) {
return DefaultBlockchain.create(createStorage(kvStore), new NoOpMetricsSystem());
} }
} }

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

@ -19,7 +19,8 @@ import static org.mockito.Mockito.verify;
import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.Blockchain;
import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage; 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.Block;
import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator;
import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator.BlockOptions; import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator.BlockOptions;
@ -56,8 +57,8 @@ public class PrunerTest {
final BlockchainStorage blockchainStorage = final BlockchainStorage blockchainStorage =
new KeyValueStoragePrefixedKeyBlockchainStorage( new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions());
final DefaultMutableBlockchain blockchain = final MutableBlockchain blockchain =
new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem);
final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 0); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 0);
pruner.start(); pruner.start();
@ -77,8 +78,8 @@ public class PrunerTest {
final BlockchainStorage blockchainStorage = final BlockchainStorage blockchainStorage =
new KeyValueStoragePrefixedKeyBlockchainStorage( new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions());
final DefaultMutableBlockchain blockchain = final MutableBlockchain blockchain =
new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem);
final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 1, 2); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 1, 2);
pruner.start(); pruner.start();
@ -103,8 +104,8 @@ public class PrunerTest {
final BlockchainStorage blockchainStorage = final BlockchainStorage blockchainStorage =
new KeyValueStoragePrefixedKeyBlockchainStorage( new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions());
final DefaultMutableBlockchain blockchain = final MutableBlockchain blockchain =
new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem);
// start pruner so it can start handling block added events // start pruner so it can start handling block added events
final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 1); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 1);
@ -150,8 +151,8 @@ public class PrunerTest {
final BlockchainStorage blockchainStorage = final BlockchainStorage blockchainStorage =
new KeyValueStoragePrefixedKeyBlockchainStorage( new KeyValueStoragePrefixedKeyBlockchainStorage(
new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions()); new InMemoryKeyValueStorage(), new MainnetBlockHeaderFunctions());
final DefaultMutableBlockchain blockchain = final MutableBlockchain blockchain =
new DefaultMutableBlockchain(genesisBlock, blockchainStorage, metricsSystem); DefaultBlockchain.createMutable(genesisBlock, blockchainStorage, metricsSystem);
final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 0); final Pruner pruner = new Pruner(markSweepPruner, blockchain, mockExecutorService, 0, 0);
pruner.start(); pruner.start();
@ -159,8 +160,7 @@ public class PrunerTest {
verify(markSweepPruner).cleanup(); verify(markSweepPruner).cleanup();
} }
private Block appendBlockWithParent( private Block appendBlockWithParent(final MutableBlockchain blockchain, final Block parent) {
final DefaultMutableBlockchain blockchain, final Block parent) {
BlockOptions options = BlockOptions options =
new BlockOptions() new BlockOptions()
.setBlockNumber(parent.getHeader().getNumber() + 1) .setBlockNumber(parent.getHeader().getNumber() + 1)

@ -18,8 +18,9 @@ import tech.pegasys.pantheon.config.JsonGenesisConfigOptions;
import tech.pegasys.pantheon.config.JsonUtil; import tech.pegasys.pantheon.config.JsonUtil;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.IncrementingNonceGenerator; 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.GenesisState;
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain;
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.BlockHeader; import tech.pegasys.pantheon.ethereum.core.BlockHeader;
@ -67,7 +68,7 @@ public class RetestethContext {
private final ReentrantLock contextLock = new ReentrantLock(); private final ReentrantLock contextLock = new ReentrantLock();
private Address coinbase; private Address coinbase;
private DefaultMutableBlockchain blockchain; private MutableBlockchain blockchain;
private ProtocolContext<Void> protocolContext; private ProtocolContext<Void> protocolContext;
private BlockchainQueries blockchainQueries; private BlockchainQueries blockchainQueries;
private ProtocolSchedule<Void> protocolSchedule; private ProtocolSchedule<Void> protocolSchedule;
@ -181,14 +182,14 @@ public class RetestethContext {
return true; return true;
} }
private static DefaultMutableBlockchain createInMemoryBlockchain(final Block genesisBlock) { private static MutableBlockchain createInMemoryBlockchain(final Block genesisBlock) {
return createInMemoryBlockchain(genesisBlock, new MainnetBlockHeaderFunctions()); return createInMemoryBlockchain(genesisBlock, new MainnetBlockHeaderFunctions());
} }
private static DefaultMutableBlockchain createInMemoryBlockchain( private static MutableBlockchain createInMemoryBlockchain(
final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) { final Block genesisBlock, final BlockHeaderFunctions blockHeaderFunctions) {
final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage(); final InMemoryKeyValueStorage keyValueStorage = new InMemoryKeyValueStorage();
return new DefaultMutableBlockchain( return DefaultBlockchain.createMutable(
genesisBlock, genesisBlock,
new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions), new KeyValueStoragePrefixedKeyBlockchainStorage(keyValueStorage, blockHeaderFunctions),
new NoOpMetricsSystem()); new NoOpMetricsSystem());
@ -238,7 +239,7 @@ public class RetestethContext {
return coinbase; return coinbase;
} }
public DefaultMutableBlockchain getBlockchain() { public MutableBlockchain getBlockchain() {
return blockchain; return blockchain;
} }

@ -14,7 +14,7 @@ package tech.pegasys.pantheon.ethereum.retesteth.methods;
import tech.pegasys.pantheon.ethereum.ProtocolContext; import tech.pegasys.pantheon.ethereum.ProtocolContext;
import tech.pegasys.pantheon.ethereum.blockcreation.EthHashBlockCreator; 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.Block;
import tech.pegasys.pantheon.ethereum.core.BlockImporter; import tech.pegasys.pantheon.ethereum.core.BlockImporter;
import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.core.Wei;
@ -61,7 +61,7 @@ public class TestMineBlocks implements JsonRpcMethod {
final RetestethClock retesethClock = context.getRetestethClock(); final RetestethClock retesethClock = context.getRetestethClock();
final ProtocolSchedule<Void> protocolSchedule = context.getProtocolSchedule(); final ProtocolSchedule<Void> protocolSchedule = context.getProtocolSchedule();
final ProtocolContext<Void> protocolContext = context.getProtocolContext(); final ProtocolContext<Void> protocolContext = context.getProtocolContext();
final DefaultMutableBlockchain blockchain = context.getBlockchain(); final MutableBlockchain blockchain = context.getBlockchain();
final HeaderValidationMode headerValidationMode = context.getHeaderValidationMode(); final HeaderValidationMode headerValidationMode = context.getHeaderValidationMode();
final EthHashBlockCreator blockCreator = final EthHashBlockCreator blockCreator =
new EthHashBlockCreator( new EthHashBlockCreator(

Loading…
Cancel
Save