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); 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); .setParentHash(remoteBlockchain.getBlockHashByNumber(i - 1).get()); final Block remoteBlock = blockDataGenerator.block(remoteOptions); final List<TransactionReceipt> remoteReceipts = blockDataGenerator.receipts(remoteBlock); remoteBlockchain.appendBlock(remoteBlock, remoteReceipts); for (long i = 0L; i <= remoteBlockchain.getChainHeadBlockNumber(); i++) { headers.add(remoteBlockchain.getBlockHeader(i).get());
@Test public void locallyGeneratedBlockInvalidatesMiningEvenIfInTurn() { // Note also - validators is an hard-ordered LIST, thus in-turn will follow said list - block_1 // should be created by Proposer, and thus will be in-turn. final CliqueMiningCoordinator coordinator = new CliqueMiningCoordinator(blockChain, minerExecutor, syncState, miningTracker); coordinator.enable(); verify(minerExecutor, times(1)).startAsyncMining(any(), any()); reset(minerExecutor); when(minerExecutor.startAsyncMining(any(), any())).thenReturn(blockMiner); final Block importedBlock = createEmptyBlock(1, blockChain.getChainHeadHash(), proposerKeys); blockChain.appendBlock(importedBlock, Lists.emptyList()); // The minerExecutor should not be invoked as the mining operation was conducted by an in-turn // validator, and the created block came from an out-turn validator. ArgumentCaptor<BlockHeader> varArgs = ArgumentCaptor.forClass(BlockHeader.class); verify(minerExecutor, times(1)).startAsyncMining(any(), varArgs.capture()); assertThat(varArgs.getValue()).isEqualTo(blockChain.getChainHeadHeader()); }
@Test public void importsValidUnorderedBlocks() throws Exception { blockchainUtil.importFirstBlocks(3); final Block valid = blockchainUtil.getBlock(3); final List<Block> nextBlocks = Collections.singletonList(valid); // Sanity check for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } // Create task final CompletableFuture<List<Block>> task = PersistBlockTask.forUnorderedBlocks( protocolSchedule, protocolContext, nextBlocks, HeaderValidationMode.FULL, ethTasksTimer) .get(); Awaitility.await().atMost(30, SECONDS).until(task::isDone); assertThat(task.isCompletedExceptionally()).isFalse(); assertThat(task.get().size()).isEqualTo(1); assertThat(task.get().contains(valid)).isTrue(); for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); } }
private BlockHeader lookupPreviousHeader( final MutableBlockchain blockchain, final BlockHeader header) { return blockchain .getBlockHeader(header.getParentHash()) .orElseThrow( () -> new IllegalStateException( String.format( "Block %s does not connect to the existing chain. Current chain head %s", header.getNumber(), blockchain.getChainHeadBlockNumber()))); }
private BlockHeader getHeaderForCurrentChainHead() { return blockchain.getBlockHeader(blockchain.getChainHeadHash()).get(); }
new BlockDataGenerator.BlockOptions() .setBlockNumber(1L) .setParentHash(blockchain.getBlockHashByNumber(0L).get()); final Block block = gen.block(options); final List<TransactionReceipt> receipts = gen.receipts(block); blockchain.appendBlock(block, receipts); EthProtocol.EthVersion.V63, 1, blockchain.getChainHead().getTotalDifficulty(), blockchain.getChainHeadHash(), blockchain.getBlockHeader(BlockHeader.GENESIS_BLOCK_NUMBER).get().getHash());
private Blockchain createMockedBlockChainWithHeadOf( final long blockNumber, final Address proposer) { when(blockInterface.getProposerOfBlock(any())).thenReturn(proposer); final BlockHeaderTestFixture headerBuilderFixture = new BlockHeaderTestFixture(); headerBuilderFixture.number(blockNumber); final BlockHeader prevBlockHeader = headerBuilderFixture.buildHeader(); // Construct a block chain and world state final MutableBlockchain blockchain = mock(MutableBlockchain.class); when(blockchain.getBlockHeader(anyLong())).thenReturn(Optional.of(prevBlockHeader)); return blockchain; }
@Test public void logsShouldBeFlaggedAsRemovedWhenBlockIsNotInCanonicalChain() { // create initial blockchain final BlockchainWithData data = setupBlockchain(3); final Block targetBlock = data.blockData.get(data.blockData.size() - 1).block; // check that logs have removed = false List<LogWithMetadata> logs = data.blockchainQueries.matchingLogs(targetBlock.getHash(), new LogsQuery.Builder().build()); assertThat(logs).isNotEmpty(); assertThat(logs).allMatch(l -> !l.isRemoved()); // Create parallel fork of length 1 final int forkBlock = 2; final int commonAncestor = 1; final BlockOptions options = new BlockOptions() .setParentHash(data.blockchain.getBlockHashByNumber(commonAncestor).get()) .setBlockNumber(forkBlock) .setDifficulty( data.blockchain.getBlockHeader(forkBlock).get().getDifficulty().plus(10L)); final Block fork = gen.block(options); final List<TransactionReceipt> forkReceipts = gen.receipts(fork); // Add fork data.blockchain.appendBlock(fork, forkReceipts); // check that logs have removed = true logs = data.blockchainQueries.matchingLogs(targetBlock.getHash(), new LogsQuery.Builder().build()); assertThat(logs).isNotEmpty(); assertThat(logs).allMatch(LogWithMetadata::isRemoved); }
@BeforeClass public static void setupClass() { genesisBlock = blockDataGenerator.genesisBlock(); localBlockchain = createInMemoryBlockchain(genesisBlock); // 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); } }
final Block chainHead = localBlockchain.getChainHeadBlock(); final Block forkBlock = gen.block(gen.nextBlockOptions(chainHead).setDifficulty(UInt256.of(0L))); localBlockchain.appendBlock(forkBlock, gen.receipts(forkBlock)); assertThat(targetBlock).isGreaterThan(localBlockchain.getChainHeadBlockNumber()); assertThat(otherBlockchain.contains(localBlockchain.getChainHead().getHash())).isFalse(); downloader.start(); while (localBlockchain.getChainHeadBlockNumber() < targetBlock) { peer.respond(responder); assertThat(localBlockchain.getChainHeadBlockNumber()).isEqualTo(targetBlock);
@Test public void getOmmerCountForInvalidNumber() { final BlockchainWithData data = setupBlockchain(3); final BlockchainQueries queries = data.blockchainQueries; final long invalidNumber = data.blockchain.getChainHeadBlockNumber() + 10; final Optional<Integer> result = queries.getOmmerCount(invalidNumber); assertFalse(result.isPresent()); }
private BlockchainWithData setupBlockchain( final int blocksToAdd, final List<Address> accountsToSetup, final List<UInt256> storageKeys) { checkArgument(blocksToAdd >= 1, "Must add at least one block to the queries"); final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); // Generate some queries data final List<BlockData> blockData = new ArrayList<>(blocksToAdd); final List<Block> blocks = gen.blockSequence(blocksToAdd, worldStateArchive, accountsToSetup, storageKeys); for (int i = 0; i < blocksToAdd; i++) { final Block block = blocks.get(i); final List<TransactionReceipt> receipts = gen.receipts(block); blockData.add(new BlockData(block, receipts)); } // Setup blockchain final MutableBlockchain blockchain = createInMemoryBlockchain(blocks.get(0)); blockData .subList(1, blockData.size()) .forEach(b -> blockchain.appendBlock(b.block, b.receipts)); return new BlockchainWithData(blockchain, blockData, worldStateArchive); }
@Test public void doesNotSyncToWorseChain() { localBlockchainSetup.importFirstBlocks(15); // Sanity check assertThat(localBlockchain.getChainHeadBlockNumber()) .isGreaterThan(BlockHeader.GENESIS_BLOCK_NUMBER); final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, otherBlockchain); final Responder responder = RespondingEthPeer.blockchainResponder(otherBlockchain); final FullSyncDownloader<?> downloader = downloader(); downloader.start(); peer.respond(responder); assertThat(syncState.syncTarget()).isNotPresent(); while (peer.hasOutstandingRequests()) { peer.respond(responder); } assertThat(syncState.syncTarget()).isNotPresent(); verify(localBlockchain, times(0)).appendBlock(any(), any()); }
gen.block(BlockOptions.create().setBlockNumber(blockchain.getChainHeadBlockNumber())); assertThat(blockchain.contains(blockToPurge.getHash())).isFalse(); assertThat(pendingBlocks.contains(blockToPurge.getHash())).isTrue(); blockchainUtil.importBlockAtIndex((int) blockchain.getChainHeadBlockNumber() + 1); assertThat(blockchain.contains(blockToPurge.getHash())).isFalse(); assertThat(pendingBlocks.contains(blockToPurge.getHash())).isTrue(); blockchainUtil.importBlockAtIndex((int) blockchain.getChainHeadBlockNumber() + 1); assertThat(blockchain.contains(blockToPurge.getHash())).isFalse(); assertThat(pendingBlocks.contains(blockToPurge.getHash())).isFalse();
@Test public void handlesPendingDuplicateAnnouncements() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); blockPropagationManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockHashesMessage newBlockHash = NewBlockHashesMessage.create( Collections.singletonList( new NewBlockHash(nextBlock.getHash(), nextBlock.getHeader().getNumber()))); final NewBlockMessage newBlock = NewBlockMessage.create( nextBlock, fullBlockchain.getTotalDifficultyByHash(nextBlock.getHash()).get()); // Broadcast messages EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, newBlock); EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, newBlockHash); EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, newBlock); // Respond final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); verify(blockchain, times(1)).appendBlock(any(), any()); }
private void verifyChainHeadIs(final Block forkBlock2) { assertThat(blockchain.getChainHeadHash()).isEqualTo(forkBlock2.getHash()); }
@Test public void shouldFailIfPeerDisconnects() { final Block block = blockDataGenerator.nextBlock(localBlockchain.getChainHeadBlock()); localBlockchain.appendBlock(block, blockDataGenerator.receipts(block));
LOG.info("Import at block {}", header.getNumber()); if (blockchain.contains(header.getHash())) { continue; previousBlockFuture.join(); return new BlockImporter.ImportResult(blockchain.getChainHead().getTotalDifficulty(), count); } finally { validationExecutor.shutdownNow();
@Test public void choosesBestPeerAsSyncTarget_byTd() { final UInt256 localTd = localBlockchain.getChainHead().getTotalDifficulty(); final Responder responder = RespondingEthPeer.blockchainResponder(otherBlockchain); final RespondingEthPeer peerA = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, localTd.plus(100)); final RespondingEthPeer peerB = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, localTd.plus(200)); final FullSyncDownloader<?> downloader = downloader(); downloader.start(); // Process until the sync target is selected while (!syncState.syncTarget().isPresent()) { RespondingEthPeer.respondOnce(responder, peerA, peerB); } assertThat(syncState.syncTarget()).isPresent(); assertThat(syncState.syncTarget().get().peer()).isEqualTo(peerB.getEthPeer()); }
@Test public void buildVoteTallyByExtractingValidatorsFromEpochBlock() { when(serialiser.validatorsInBlock(any())).thenReturn(asList(subject, validator1)); final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); final BlockHeader header = headerBuilder.buildHeader(); when(blockchain.getChainHeadBlockNumber()).thenReturn(EPOCH_LENGTH); when(blockchain.getBlockHeader(EPOCH_LENGTH)).thenReturn(Optional.of(header)); final VoteTally voteTally = updater.buildVoteTallyFromBlockchain(blockchain); assertThat(voteTally.getValidators()).containsExactly(subject, validator1); }