mirror of https://github.com/hyperledger/besu
[PIE-1810] Update export subcommand to export blocks in rlp format (#1852)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
a5daeba71d
commit
f9e50ae8c6
@ -0,0 +1,94 @@ |
||||
/* |
||||
* 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.chainexport; |
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Block; |
||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.Optional; |
||||
|
||||
import org.apache.logging.log4j.LogManager; |
||||
import org.apache.logging.log4j.Logger; |
||||
|
||||
/** Pantheon Block Export Util. */ |
||||
public abstract class BlockExporter { |
||||
private static final Logger LOG = LogManager.getLogger(); |
||||
private final Blockchain blockchain; |
||||
|
||||
protected BlockExporter(final Blockchain blockchain) { |
||||
this.blockchain = blockchain; |
||||
} |
||||
|
||||
/** |
||||
* Export blocks that are stored in Pantheon's block storage. |
||||
* |
||||
* @param outputFile the path at which to save the exported block data |
||||
* @param maybeStartBlock the starting index of the block list to export (inclusive) |
||||
* @param maybeEndBlock the ending index of the block list to export (exclusive), if not specified |
||||
* a single block will be export |
||||
* @throws IOException if an I/O error occurs while writing data to disk |
||||
*/ |
||||
public void exportBlocks( |
||||
final File outputFile, |
||||
final Optional<Long> maybeStartBlock, |
||||
final Optional<Long> maybeEndBlock) |
||||
throws IOException { |
||||
|
||||
// Get range to export
|
||||
final long startBlock = maybeStartBlock.orElse(BlockHeader.GENESIS_BLOCK_NUMBER); |
||||
final long endBlock = maybeEndBlock.orElse(blockchain.getChainHeadBlockNumber() + 1L); |
||||
checkArgument(startBlock >= 0 && endBlock >= 0, "Start and end blocks must be greater than 0."); |
||||
checkArgument(startBlock < endBlock, "Start block must be less than end block"); |
||||
|
||||
// Append to file if a range is specified
|
||||
final boolean append = maybeStartBlock.isPresent(); |
||||
FileOutputStream outputStream = new FileOutputStream(outputFile, append); |
||||
|
||||
LOG.info( |
||||
"Exporting blocks [{},{}) to file {} (appending: {})", |
||||
startBlock, |
||||
endBlock, |
||||
outputFile.toString(), |
||||
Boolean.toString(append)); |
||||
|
||||
long blockNumber = 0L; |
||||
for (long i = startBlock; i < endBlock; i++) { |
||||
Optional<Hash> blockHash = blockchain.getBlockHashByNumber(i); |
||||
if (blockHash.isEmpty()) { |
||||
LOG.warn("Unable to export blocks [{} - {}). Blocks not found.", i, endBlock); |
||||
break; |
||||
} |
||||
|
||||
final Block block = blockchain.getBlockByHash(blockHash.get()); |
||||
blockNumber = block.getHeader().getNumber(); |
||||
if (blockNumber % 100 == 0) { |
||||
LOG.info("Export at block {}", blockNumber); |
||||
} |
||||
|
||||
exportBlock(outputStream, block); |
||||
} |
||||
|
||||
outputStream.close(); |
||||
LOG.info("Export complete at block {}", blockNumber); |
||||
} |
||||
|
||||
protected abstract void exportBlock(final FileOutputStream outputStream, final Block block) |
||||
throws IOException; |
||||
} |
@ -0,0 +1,35 @@ |
||||
/* |
||||
* Copyright 2019 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.chainexport; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Block; |
||||
import tech.pegasys.pantheon.ethereum.rlp.RLP; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||
|
||||
import java.io.FileOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
public class RlpBlockExporter extends BlockExporter { |
||||
|
||||
public RlpBlockExporter(final Blockchain blockchain) { |
||||
super(blockchain); |
||||
} |
||||
|
||||
@Override |
||||
protected void exportBlock(final FileOutputStream outputStream, final Block block) |
||||
throws IOException { |
||||
final BytesValue rlp = RLP.encode(block::writeTo); |
||||
outputStream.write(rlp.getArrayUnsafe()); |
||||
} |
||||
} |
@ -0,0 +1,17 @@ |
||||
/* |
||||
* Copyright 2019 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.cli.subcommands.blocks; |
||||
|
||||
public enum BlockExportFormat { |
||||
RLP |
||||
} |
@ -1,88 +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.util; |
||||
|
||||
import tech.pegasys.pantheon.controller.PantheonController; |
||||
import tech.pegasys.pantheon.ethereum.ProtocolContext; |
||||
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Block; |
||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import com.google.common.base.MoreObjects; |
||||
|
||||
/** Pantheon Block Export Util. */ |
||||
public class BlockExporter { |
||||
|
||||
/** |
||||
* Export blocks that are stored in Pantheon's block storage. |
||||
* |
||||
* @param pantheonController the PantheonController that defines blockchain behavior |
||||
* @param <C> the consensus context type |
||||
* @param startBlock the starting index of the block list to export (inclusive) |
||||
* @param endBlock the ending index of the block list to export (exclusive), if not specified a |
||||
* single block will be export |
||||
* @return the export result |
||||
*/ |
||||
public <C> ExportResult exportBlockchain( |
||||
final PantheonController<C> pantheonController, final Long startBlock, final Long endBlock) { |
||||
|
||||
final ProtocolContext<C> context = pantheonController.getProtocolContext(); |
||||
final MutableBlockchain blockchain = context.getBlockchain(); |
||||
|
||||
final Long sanitizedEndBlock = sanitizedEndBlockIndex(startBlock, endBlock); |
||||
|
||||
final List<Block> blocks = new ArrayList<>(); |
||||
for (long currentBlockIndex = startBlock; |
||||
currentBlockIndex < sanitizedEndBlock; |
||||
currentBlockIndex += 1) { |
||||
Optional<Hash> blockHashByNumber = blockchain.getBlockHashByNumber(currentBlockIndex); |
||||
blockHashByNumber.ifPresent(hash -> blocks.add(blockchain.getBlockByHash(hash))); |
||||
} |
||||
|
||||
final boolean allBlocksAreFound = blocks.size() == (sanitizedEndBlock - startBlock); |
||||
|
||||
return new ExportResult(blocks, allBlocksAreFound); |
||||
} |
||||
|
||||
private Long sanitizedEndBlockIndex(final Long startBlock, final Long endBlock) { |
||||
if (endBlock == null) { |
||||
return startBlock + 1; |
||||
} else { |
||||
return endBlock; |
||||
} |
||||
} |
||||
|
||||
public static final class ExportResult { |
||||
|
||||
public final List<Block> blocks; |
||||
|
||||
public final boolean allBlocksAreFound; |
||||
|
||||
ExportResult(final List<Block> blocks, final boolean allBlocksAreFound) { |
||||
this.blocks = blocks; |
||||
this.allBlocksAreFound = allBlocksAreFound; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return MoreObjects.toStringHelper(this) |
||||
.add("blocks", blocks) |
||||
.add("allBlocksAreFound", allBlocksAreFound) |
||||
.toString(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,245 @@ |
||||
/* |
||||
* 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.chainexport; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
||||
|
||||
import tech.pegasys.pantheon.chainimport.RlpBlockImporter; |
||||
import tech.pegasys.pantheon.config.GenesisConfigFile; |
||||
import tech.pegasys.pantheon.controller.PantheonController; |
||||
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||
import tech.pegasys.pantheon.ethereum.chain.Blockchain; |
||||
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.InMemoryStorageProvider; |
||||
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; |
||||
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; |
||||
import tech.pegasys.pantheon.ethereum.eth.EthProtocolConfiguration; |
||||
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; |
||||
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolConfiguration; |
||||
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; |
||||
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions; |
||||
import tech.pegasys.pantheon.ethereum.util.RawBlockIterator; |
||||
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; |
||||
import tech.pegasys.pantheon.testutil.BlockTestUtil; |
||||
import tech.pegasys.pantheon.testutil.TestClock; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.file.Path; |
||||
import java.util.Optional; |
||||
|
||||
import org.junit.BeforeClass; |
||||
import org.junit.ClassRule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
|
||||
/** Tests for {@link BlockExporter}. */ |
||||
public final class RlpBlockExporterTest { |
||||
|
||||
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); |
||||
private static Blockchain blockchain; |
||||
private static long chainHead; |
||||
private static ProtocolSchedule<?> protocolSchedule; |
||||
|
||||
@BeforeClass |
||||
public static void setupBlockchain() throws IOException { |
||||
final PantheonController<?> controller = createController(); |
||||
final Path blocks = folder.newFile("1000.blocks").toPath(); |
||||
BlockTestUtil.write1000Blocks(blocks); |
||||
blockchain = importBlocks(controller, blocks); |
||||
chainHead = blockchain.getChainHeadBlockNumber(); |
||||
protocolSchedule = controller.getProtocolSchedule(); |
||||
} |
||||
|
||||
private static Blockchain importBlocks( |
||||
final PantheonController<?> controller, final Path blocksFile) throws IOException { |
||||
final RlpBlockImporter blockImporter = new RlpBlockImporter(); |
||||
|
||||
blockImporter.importBlockchain(blocksFile, controller); |
||||
return controller.getProtocolContext().getBlockchain(); |
||||
} |
||||
|
||||
private static PantheonController<?> createController() throws IOException { |
||||
final Path dataDir = folder.newFolder().toPath(); |
||||
return new PantheonController.Builder() |
||||
.fromGenesisConfig(GenesisConfigFile.mainnet()) |
||||
.synchronizerConfiguration(SynchronizerConfiguration.builder().build()) |
||||
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) |
||||
.storageProvider(new InMemoryStorageProvider()) |
||||
.networkId(1) |
||||
.miningParameters(new MiningParametersTestBuilder().enabled(false).build()) |
||||
.nodeKeys(KeyPair.generate()) |
||||
.metricsSystem(new NoOpMetricsSystem()) |
||||
.privacyParameters(PrivacyParameters.DEFAULT) |
||||
.dataDirectory(dataDir) |
||||
.clock(TestClock.fixed()) |
||||
.transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) |
||||
.build(); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_noBounds() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
exporter.exportBlocks(outputPath, Optional.empty(), Optional.empty()); |
||||
|
||||
// Iterate over blocks and check that they match expectations
|
||||
RawBlockIterator blockIterator = getBlockIterator(outputPath.toPath()); |
||||
long currentBlockNumber = 0; |
||||
while (blockIterator.hasNext()) { |
||||
final Block actual = blockIterator.next(); |
||||
final Block expected = getBlock(blockchain, currentBlockNumber); |
||||
assertThat(actual).isEqualTo(expected); |
||||
currentBlockNumber++; |
||||
} |
||||
|
||||
// Check that we iterated to the end of the chain
|
||||
assertThat(currentBlockNumber).isEqualTo(chainHead + 1L); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_withLowerBound() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
final long lowerBound = 990; |
||||
exporter.exportBlocks(outputPath, Optional.of(lowerBound), Optional.empty()); |
||||
|
||||
// Iterate over blocks and check that they match expectations
|
||||
RawBlockIterator blockIterator = getBlockIterator(outputPath.toPath()); |
||||
long currentBlockNumber = lowerBound; |
||||
while (blockIterator.hasNext()) { |
||||
final Block actual = blockIterator.next(); |
||||
final Block expected = getBlock(blockchain, currentBlockNumber); |
||||
assertThat(actual).isEqualTo(expected); |
||||
currentBlockNumber++; |
||||
} |
||||
|
||||
// Check that we iterated to the end of the chain
|
||||
assertThat(currentBlockNumber).isEqualTo(chainHead + 1L); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_withUpperBound() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
final long upperBound = 10; |
||||
exporter.exportBlocks(outputPath, Optional.empty(), Optional.of(upperBound)); |
||||
|
||||
// Iterate over blocks and check that they match expectations
|
||||
RawBlockIterator blockIterator = getBlockIterator(outputPath.toPath()); |
||||
long currentBlockNumber = 0; |
||||
while (blockIterator.hasNext()) { |
||||
final Block actual = blockIterator.next(); |
||||
final Block expected = getBlock(blockchain, currentBlockNumber); |
||||
assertThat(actual).isEqualTo(expected); |
||||
currentBlockNumber++; |
||||
} |
||||
|
||||
// Check that we iterated to the end of the chain
|
||||
assertThat(currentBlockNumber).isEqualTo(upperBound); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_withUpperAndLowerBounds() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
final long lowerBound = 5; |
||||
final long upperBound = 10; |
||||
exporter.exportBlocks(outputPath, Optional.of(lowerBound), Optional.of(upperBound)); |
||||
|
||||
// Iterate over blocks and check that they match expectations
|
||||
RawBlockIterator blockIterator = getBlockIterator(outputPath.toPath()); |
||||
long currentBlockNumber = lowerBound; |
||||
while (blockIterator.hasNext()) { |
||||
final Block actual = blockIterator.next(); |
||||
final Block expected = getBlock(blockchain, currentBlockNumber); |
||||
assertThat(actual).isEqualTo(expected); |
||||
currentBlockNumber++; |
||||
} |
||||
|
||||
// Check that we iterated to the end of the chain
|
||||
assertThat(currentBlockNumber).isEqualTo(upperBound); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_withRangeBeyondChainHead() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
final long lowerBound = chainHead - 10; |
||||
final long upperBound = chainHead + 10; |
||||
exporter.exportBlocks(outputPath, Optional.of(lowerBound), Optional.of(upperBound)); |
||||
|
||||
// Iterate over blocks and check that they match expectations
|
||||
RawBlockIterator blockIterator = getBlockIterator(outputPath.toPath()); |
||||
long currentBlockNumber = lowerBound; |
||||
while (blockIterator.hasNext()) { |
||||
final Block actual = blockIterator.next(); |
||||
final Block expected = getBlock(blockchain, currentBlockNumber); |
||||
assertThat(actual).isEqualTo(expected); |
||||
currentBlockNumber++; |
||||
} |
||||
|
||||
// Check that we iterated to the end of the chain
|
||||
assertThat(currentBlockNumber).isEqualTo(chainHead + 1L); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_negativeStartNumber() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
assertThatThrownBy(() -> exporter.exportBlocks(outputPath, Optional.of(-1L), Optional.empty())) |
||||
.isInstanceOf(IllegalArgumentException.class) |
||||
.hasMessageContaining("greater than 0"); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_negativeEndNumber() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
assertThatThrownBy(() -> exporter.exportBlocks(outputPath, Optional.empty(), Optional.of(-1L))) |
||||
.isInstanceOf(IllegalArgumentException.class) |
||||
.hasMessageContaining("greater than 0"); |
||||
} |
||||
|
||||
@Test |
||||
public void exportBlocks_outOfOrderBounds() throws IOException { |
||||
final File outputPath = folder.newFile(); |
||||
final RlpBlockExporter exporter = new RlpBlockExporter(blockchain); |
||||
|
||||
assertThatThrownBy(() -> exporter.exportBlocks(outputPath, Optional.of(10L), Optional.of(2L))) |
||||
.isInstanceOf(IllegalArgumentException.class) |
||||
.hasMessageContaining("Start block must be less than end block"); |
||||
} |
||||
|
||||
private RawBlockIterator getBlockIterator(final Path blocks) throws IOException { |
||||
return new RawBlockIterator( |
||||
blocks, |
||||
rlp -> |
||||
BlockHeader.readFrom(rlp, ScheduleBasedBlockHeaderFunctions.create(protocolSchedule))); |
||||
} |
||||
|
||||
private Block getBlock(final Blockchain blockchain, final long blockNumber) { |
||||
final BlockHeader header = blockchain.getBlockHeader(blockNumber).get(); |
||||
final BlockBody body = blockchain.getBlockBody(header.getHash()).get(); |
||||
return new Block(header, body); |
||||
} |
||||
} |
@ -1,111 +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.util; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.config.GenesisConfigFile; |
||||
import tech.pegasys.pantheon.controller.PantheonController; |
||||
import tech.pegasys.pantheon.crypto.SECP256K1; |
||||
import tech.pegasys.pantheon.ethereum.chain.MutableBlockchain; |
||||
import tech.pegasys.pantheon.ethereum.core.Block; |
||||
import tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider; |
||||
import tech.pegasys.pantheon.ethereum.core.MiningParametersTestBuilder; |
||||
import tech.pegasys.pantheon.ethereum.core.PrivacyParameters; |
||||
import tech.pegasys.pantheon.ethereum.eth.EthProtocolConfiguration; |
||||
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration; |
||||
import tech.pegasys.pantheon.ethereum.eth.transactions.TransactionPoolConfiguration; |
||||
import tech.pegasys.pantheon.metrics.noop.NoOpMetricsSystem; |
||||
import tech.pegasys.pantheon.testutil.BlockTestUtil; |
||||
import tech.pegasys.pantheon.testutil.TestClock; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.file.Path; |
||||
|
||||
import org.junit.BeforeClass; |
||||
import org.junit.ClassRule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.TemporaryFolder; |
||||
|
||||
/** Tests for {@link BlockExporter}. */ |
||||
public final class BlockExporterTest { |
||||
|
||||
@ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); |
||||
|
||||
private static PantheonController<?> targetController; |
||||
|
||||
private final BlockExporter blockExporter = new BlockExporter(); |
||||
|
||||
@BeforeClass |
||||
public static void initPantheonController() throws IOException { |
||||
final BlockImporter blockImporter = new BlockImporter(); |
||||
final Path dataDir = folder.newFolder().toPath(); |
||||
final Path source = dataDir.resolve("1000.blocks"); |
||||
BlockTestUtil.write1000Blocks(source); |
||||
targetController = |
||||
new PantheonController.Builder() |
||||
.fromGenesisConfig(GenesisConfigFile.mainnet()) |
||||
.synchronizerConfiguration(SynchronizerConfiguration.builder().build()) |
||||
.ethProtocolConfiguration(EthProtocolConfiguration.defaultConfig()) |
||||
.storageProvider(new InMemoryStorageProvider()) |
||||
.networkId(1) |
||||
.miningParameters(new MiningParametersTestBuilder().enabled(false).build()) |
||||
.nodeKeys(SECP256K1.KeyPair.generate()) |
||||
.metricsSystem(new NoOpMetricsSystem()) |
||||
.privacyParameters(PrivacyParameters.DEFAULT) |
||||
.dataDirectory(dataDir) |
||||
.clock(TestClock.fixed()) |
||||
.transactionPoolConfiguration(TransactionPoolConfiguration.builder().build()) |
||||
.build(); |
||||
blockImporter.importBlockchain(source, targetController); |
||||
} |
||||
|
||||
@Test |
||||
public void callingBlockExporterWithOnlyStartBlockShouldReturnOneBlock() throws Exception { |
||||
|
||||
final long startBlock = 0L; |
||||
|
||||
final MutableBlockchain blockchain = targetController.getProtocolContext().getBlockchain(); |
||||
|
||||
final Block blockFromBlockchain = |
||||
blockchain.getBlockByHash(blockchain.getBlockHashByNumber(startBlock).get()); |
||||
|
||||
BlockExporter.ExportResult exportResult = |
||||
blockExporter.exportBlockchain(targetController, startBlock, null); |
||||
|
||||
assertThat(exportResult.blocks).contains(blockFromBlockchain); |
||||
} |
||||
|
||||
@Test |
||||
public void callingBlockExporterWithStartBlockAndBlockShouldReturnSeveralBlocks() |
||||
throws Exception { |
||||
|
||||
final long startBlock = 0L; |
||||
final long endBlock = 1L; |
||||
|
||||
final MutableBlockchain blockchain = targetController.getProtocolContext().getBlockchain(); |
||||
|
||||
final Block blockFromBlockchain = |
||||
blockchain.getBlockByHash(blockchain.getBlockHashByNumber(startBlock).get()); |
||||
|
||||
final Block secondBlockFromBlockchain = |
||||
blockchain.getBlockByHash(blockchain.getBlockHashByNumber(endBlock - 1).get()); |
||||
|
||||
BlockExporter.ExportResult exportResult = |
||||
blockExporter.exportBlockchain(targetController, startBlock, endBlock); |
||||
|
||||
assertThat(exportResult.blocks) |
||||
.contains(blockFromBlockchain) |
||||
.contains(secondBlockFromBlockchain); |
||||
} |
||||
} |
Loading…
Reference in new issue