mirror of https://github.com/hyperledger/besu
parameterize BlockchainUtilTest (#57)
parent
92fefe60e5
commit
d38a5a3f84
@ -0,0 +1,135 @@ |
|||||||
|
package tech.pegasys.pantheon.ethereum.util; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
|
||||||
|
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.TransactionReceipt; |
||||||
|
import tech.pegasys.pantheon.ethereum.db.DefaultMutableBlockchain; |
||||||
|
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; |
||||||
|
import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; |
||||||
|
import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; |
||||||
|
import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; |
||||||
|
import tech.pegasys.pantheon.util.uint.UInt256; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.OptionalInt; |
||||||
|
import java.util.Random; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.BeforeClass; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.junit.runners.Parameterized; |
||||||
|
|
||||||
|
@RunWith(Parameterized.class) |
||||||
|
public class BlockchainUtilParameterizedTest { |
||||||
|
private static final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); |
||||||
|
private static final Random random = new Random(1337); |
||||||
|
|
||||||
|
private static final int chainHeight = 89; |
||||||
|
private final int commonAncestorHeight; |
||||||
|
private static Block genesisBlock; |
||||||
|
private static KeyValueStorage localKvStore; |
||||||
|
private static DefaultMutableBlockchain localBlockchain; |
||||||
|
|
||||||
|
private KeyValueStorage remoteKvStore; |
||||||
|
private DefaultMutableBlockchain remoteBlockchain; |
||||||
|
|
||||||
|
private BlockHeader commonHeader; |
||||||
|
private List<BlockHeader> headers; |
||||||
|
|
||||||
|
public BlockchainUtilParameterizedTest(final int commonAncestorHeight) { |
||||||
|
this.commonAncestorHeight = commonAncestorHeight; |
||||||
|
} |
||||||
|
|
||||||
|
@BeforeClass |
||||||
|
public static void setupClass() { |
||||||
|
genesisBlock = blockDataGenerator.genesisBlock(); |
||||||
|
localKvStore = new InMemoryKeyValueStorage(); |
||||||
|
localBlockchain = |
||||||
|
new DefaultMutableBlockchain( |
||||||
|
genesisBlock, localKvStore, MainnetBlockHashFunction::createHash); |
||||||
|
// Setup local chain.
|
||||||
|
for (int i = 1; i <= chainHeight; i++) { |
||||||
|
final BlockDataGenerator.BlockOptions options = |
||||||
|
new BlockDataGenerator.BlockOptions() |
||||||
|
.setBlockNumber(i) |
||||||
|
.setParentHash(localBlockchain.getBlockHashByNumber(i - 1).get()); |
||||||
|
final Block block = blockDataGenerator.block(options); |
||||||
|
final List<TransactionReceipt> receipts = blockDataGenerator.receipts(block); |
||||||
|
localBlockchain.appendBlock(block, receipts); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setup() { |
||||||
|
remoteKvStore = new InMemoryKeyValueStorage(); |
||||||
|
remoteBlockchain = |
||||||
|
new DefaultMutableBlockchain( |
||||||
|
genesisBlock, remoteKvStore, MainnetBlockHashFunction::createHash); |
||||||
|
|
||||||
|
commonHeader = genesisBlock.getHeader(); |
||||||
|
for (long i = 1; i <= commonAncestorHeight; i++) { |
||||||
|
commonHeader = localBlockchain.getBlockHeader(i).get(); |
||||||
|
final List<TransactionReceipt> receipts = |
||||||
|
localBlockchain.getTxReceipts(commonHeader.getHash()).get(); |
||||||
|
final BlockBody commonBody = localBlockchain.getBlockBody(commonHeader.getHash()).get(); |
||||||
|
remoteBlockchain.appendBlock(new Block(commonHeader, commonBody), receipts); |
||||||
|
} |
||||||
|
// Remaining blocks are disparate.
|
||||||
|
for (long i = commonAncestorHeight + 1L; i <= chainHeight; i++) { |
||||||
|
final BlockDataGenerator.BlockOptions localOptions = |
||||||
|
new BlockDataGenerator.BlockOptions() |
||||||
|
.setBlockNumber(i) |
||||||
|
.setParentHash(localBlockchain.getBlockHashByNumber(i - 1).get()); |
||||||
|
final Block localBlock = blockDataGenerator.block(localOptions); |
||||||
|
final List<TransactionReceipt> localReceipts = blockDataGenerator.receipts(localBlock); |
||||||
|
localBlockchain.appendBlock(localBlock, localReceipts); |
||||||
|
|
||||||
|
final BlockDataGenerator.BlockOptions remoteOptions = |
||||||
|
new BlockDataGenerator.BlockOptions() |
||||||
|
.setDifficulty(UInt256.ONE) // differentiator
|
||||||
|
.setBlockNumber(i) |
||||||
|
.setParentHash(remoteBlockchain.getBlockHashByNumber(i - 1).get()); |
||||||
|
final Block remoteBlock = blockDataGenerator.block(remoteOptions); |
||||||
|
final List<TransactionReceipt> remoteReceipts = blockDataGenerator.receipts(remoteBlock); |
||||||
|
remoteBlockchain.appendBlock(remoteBlock, remoteReceipts); |
||||||
|
} |
||||||
|
headers = new ArrayList<>(); |
||||||
|
for (long i = 0L; i <= remoteBlockchain.getChainHeadBlockNumber(); i++) { |
||||||
|
headers.add(remoteBlockchain.getBlockHeader(i).get()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Parameterized.Parameters(name = "commonAncestor={0}") |
||||||
|
public static Collection<Object[]> parameters() { |
||||||
|
final List<Object[]> params = new ArrayList<>(); |
||||||
|
params.add(new Object[] {0}); |
||||||
|
params.add(new Object[] {chainHeight}); |
||||||
|
params.add(new Object[] {random.nextInt(chainHeight - 1) + 1}); |
||||||
|
params.add(new Object[] {random.nextInt(chainHeight - 1) + 1}); |
||||||
|
params.add(new Object[] {random.nextInt(chainHeight - 1) + 1}); |
||||||
|
return params; |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void searchesAscending() { |
||||||
|
OptionalInt maybeAncestorNumber = |
||||||
|
BlockchainUtil.findHighestKnownBlockIndex(localBlockchain, headers, true); |
||||||
|
assertThat(maybeAncestorNumber.getAsInt()).isEqualTo(Math.toIntExact(commonHeader.getNumber())); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void searchesDescending() { |
||||||
|
Collections.reverse(headers); |
||||||
|
OptionalInt maybeAncestorNumber = |
||||||
|
BlockchainUtil.findHighestKnownBlockIndex(localBlockchain, headers, false); |
||||||
|
assertThat(maybeAncestorNumber.getAsInt()) |
||||||
|
.isEqualTo(Math.toIntExact(chainHeight - commonHeader.getNumber())); |
||||||
|
} |
||||||
|
} |
@ -1,119 +0,0 @@ |
|||||||
package tech.pegasys.pantheon.ethereum.util; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
import static sun.security.krb5.Confounder.bytes; |
|
||||||
|
|
||||||
import tech.pegasys.pantheon.ethereum.core.Address; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.Block; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.BlockBody; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.BlockHeader; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.BlockHeaderBuilder; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.Hash; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.LogsBloomFilter; |
|
||||||
import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; |
|
||||||
import tech.pegasys.pantheon.ethereum.db.DefaultMutableBlockchain; |
|
||||||
import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockHashFunction; |
|
||||||
import tech.pegasys.pantheon.ethereum.testutil.BlockDataGenerator; |
|
||||||
import tech.pegasys.pantheon.services.kvstore.InMemoryKeyValueStorage; |
|
||||||
import tech.pegasys.pantheon.services.kvstore.KeyValueStorage; |
|
||||||
import tech.pegasys.pantheon.util.bytes.Bytes32; |
|
||||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
|
||||||
import tech.pegasys.pantheon.util.uint.UInt256; |
|
||||||
|
|
||||||
import java.time.Instant; |
|
||||||
import java.time.temporal.ChronoUnit; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.List; |
|
||||||
import java.util.OptionalInt; |
|
||||||
|
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
public class BlockchainUtilTest { |
|
||||||
|
|
||||||
@Test |
|
||||||
public void shouldReturnIndexOfCommonBlockForAscendingOrder() { |
|
||||||
BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); |
|
||||||
|
|
||||||
BlockHeader genesisHeader = |
|
||||||
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(Instant.now().truncatedTo(ChronoUnit.SECONDS).getEpochSecond()) |
|
||||||
.extraData(Bytes32.wrap(bytes(Bytes32.SIZE))) |
|
||||||
.mixHash(Hash.ZERO) |
|
||||||
.nonce(0L) |
|
||||||
.blockHashFunction(MainnetBlockHashFunction::createHash) |
|
||||||
.buildBlockHeader(); |
|
||||||
BlockBody genesisBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); |
|
||||||
Block genesisBlock = new Block(genesisHeader, genesisBody); |
|
||||||
|
|
||||||
KeyValueStorage kvStoreLocal = new InMemoryKeyValueStorage(); |
|
||||||
KeyValueStorage kvStoreRemote = new InMemoryKeyValueStorage(); |
|
||||||
|
|
||||||
DefaultMutableBlockchain blockchainLocal = |
|
||||||
new DefaultMutableBlockchain( |
|
||||||
genesisBlock, kvStoreLocal, MainnetBlockHashFunction::createHash); |
|
||||||
DefaultMutableBlockchain blockchainRemote = |
|
||||||
new DefaultMutableBlockchain( |
|
||||||
genesisBlock, kvStoreRemote, MainnetBlockHashFunction::createHash); |
|
||||||
|
|
||||||
// Common chain segment
|
|
||||||
Block commonBlock = null; |
|
||||||
for (long i = 1; i <= 3; i++) { |
|
||||||
BlockDataGenerator.BlockOptions options = |
|
||||||
new BlockDataGenerator.BlockOptions() |
|
||||||
.setBlockNumber(i) |
|
||||||
.setParentHash(blockchainLocal.getBlockHashByNumber(i - 1).get()); |
|
||||||
commonBlock = blockDataGenerator.block(options); |
|
||||||
List<TransactionReceipt> receipts = blockDataGenerator.receipts(commonBlock); |
|
||||||
blockchainLocal.appendBlock(commonBlock, receipts); |
|
||||||
blockchainRemote.appendBlock(commonBlock, receipts); |
|
||||||
} |
|
||||||
|
|
||||||
// Populate local chain
|
|
||||||
for (long i = 4; i <= 9; i++) { |
|
||||||
BlockDataGenerator.BlockOptions optionsLocal = |
|
||||||
new BlockDataGenerator.BlockOptions() |
|
||||||
.setDifficulty(UInt256.ZERO) // differentiator
|
|
||||||
.setBlockNumber(i) |
|
||||||
.setParentHash(blockchainLocal.getBlockHashByNumber(i - 1).get()); |
|
||||||
Block blockLocal = blockDataGenerator.block(optionsLocal); |
|
||||||
List<TransactionReceipt> receiptsLocal = blockDataGenerator.receipts(blockLocal); |
|
||||||
blockchainLocal.appendBlock(blockLocal, receiptsLocal); |
|
||||||
} |
|
||||||
|
|
||||||
// Populate remote chain
|
|
||||||
for (long i = 4; i <= 9; i++) { |
|
||||||
BlockDataGenerator.BlockOptions optionsRemote = |
|
||||||
new BlockDataGenerator.BlockOptions() |
|
||||||
.setDifficulty(UInt256.ONE) |
|
||||||
.setBlockNumber(i) |
|
||||||
.setParentHash(blockchainRemote.getBlockHashByNumber(i - 1).get()); |
|
||||||
Block blockRemote = blockDataGenerator.block(optionsRemote); |
|
||||||
List<TransactionReceipt> receiptsRemote = blockDataGenerator.receipts(blockRemote); |
|
||||||
blockchainRemote.appendBlock(blockRemote, receiptsRemote); |
|
||||||
} |
|
||||||
|
|
||||||
// Create a list of headers...
|
|
||||||
List<BlockHeader> headers = new ArrayList<>(); |
|
||||||
for (long i = 0L; i < blockchainRemote.getChainHeadBlockNumber(); i++) { |
|
||||||
headers.add(blockchainRemote.getBlockHeader(i).get()); |
|
||||||
} |
|
||||||
|
|
||||||
OptionalInt maybeAncestorNumber = |
|
||||||
BlockchainUtil.findHighestKnownBlockIndex(blockchainLocal, headers, true); |
|
||||||
|
|
||||||
assertThat(maybeAncestorNumber.getAsInt()) |
|
||||||
.isEqualTo(Math.toIntExact(commonBlock.getHeader().getNumber())); |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue