@Test public void cancelAfterRunning() throws Exception { blockchainUtil.importFirstBlocks(3); final Block nextBlock = blockchainUtil.getBlock(3); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); // Create task final PersistBlockTask<Void> task = PersistBlockTask.create( protocolSchedule, protocolContext, nextBlock, HeaderValidationMode.FULL, ethTasksTimer); final PersistBlockTask<Void> taskSpy = Mockito.spy(task); Mockito.doNothing().when(taskSpy).executeTaskTimed(); final CompletableFuture<Block> result = taskSpy.run(); taskSpy.cancel(); assertThat(result.isCancelled()).isTrue(); assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } }
@Test public void importsValidBlock() throws Exception { blockchainUtil.importFirstBlocks(3); final Block nextBlock = blockchainUtil.getBlock(3); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); // Create task final PersistBlockTask<Void> task = PersistBlockTask.create( protocolSchedule, protocolContext, nextBlock, HeaderValidationMode.FULL, ethTasksTimer); final CompletableFuture<Block> result = task.run(); Awaitility.await().atMost(30, SECONDS).until(result::isDone); assertThat(result.isCompletedExceptionally()).isFalse(); assertThat(result.get()).isEqualTo(nextBlock); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); }
@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(); } }
@Test public void cancelBeforeRunning() throws Exception { blockchainUtil.importFirstBlocks(3); final Block nextBlock = blockchainUtil.getBlock(3); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); // Create task final PersistBlockTask<Void> task = PersistBlockTask.create( protocolSchedule, protocolContext, nextBlock, HeaderValidationMode.FULL, ethTasksTimer); task.cancel(); final CompletableFuture<Block> result = task.run(); assertThat(result.isCancelled()).isTrue(); assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); }
@Test public void importsUnorderedBlocksWithMixOfValidAndInvalidBlocks() throws Exception { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final Block valid = blockchainUtil.getBlock(3); final Block invalid = gen.block(); final List<Block> nextBlocks = Arrays.asList(invalid, 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(); assertThat(blockchain.contains(valid.getHash())).isTrue(); assertThat(blockchain.contains(invalid.getHash())).isFalse(); }
@Test public void failsToImportInvalidBlockSequenceWhereFirstBlockFails() throws Exception { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final List<Block> nextBlocks = Arrays.asList(gen.block(), blockchainUtil.getBlock(3)); // Sanity check for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } // Create task final CompletableFuture<List<Block>> task = PersistBlockTask.forSequentialBlocks( protocolSchedule, protocolContext, nextBlocks, HeaderValidationMode.FULL, ethTasksTimer) .get(); Awaitility.await().atMost(30, SECONDS).until(task::isDone); assertThat(task.isCompletedExceptionally()).isTrue(); assertThatThrownBy(task::get).hasCauseInstanceOf(InvalidBlockException.class); assertThat(blockchain.contains(nextBlocks.get(0).getHash())).isFalse(); assertThat(blockchain.contains(nextBlocks.get(1).getHash())).isFalse(); }
@Test public void failsToImportInvalidBlockSequenceWhereSecondBlockFails() throws Exception { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final List<Block> nextBlocks = Arrays.asList(blockchainUtil.getBlock(3), gen.block()); // Sanity check for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } // Create task final CompletableFuture<List<Block>> task = PersistBlockTask.forSequentialBlocks( protocolSchedule, protocolContext, nextBlocks, HeaderValidationMode.FULL, ethTasksTimer) .get(); Awaitility.await().atMost(30, SECONDS).until(task::isDone); assertThat(task.isCompletedExceptionally()).isTrue(); assertThatThrownBy(task::get).hasCauseInstanceOf(InvalidBlockException.class); assertThat(blockchain.contains(nextBlocks.get(0).getHash())).isTrue(); assertThat(blockchain.contains(nextBlocks.get(1).getHash())).isFalse(); }
@Test public void importsInvalidUnorderedBlock() throws Exception { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final Block invalid = gen.block(); final List<Block> nextBlocks = Collections.singletonList(invalid); // 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()).isTrue(); for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } }
@Test public void importsValidBlockSequence() throws Exception { blockchainUtil.importFirstBlocks(3); final List<Block> nextBlocks = Arrays.asList(blockchainUtil.getBlock(3), blockchainUtil.getBlock(4)); // Sanity check for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } // Create task final CompletableFuture<List<Block>> task = PersistBlockTask.forSequentialBlocks( protocolSchedule, protocolContext, nextBlocks, HeaderValidationMode.FULL, ethTasksTimer) .get(); Awaitility.await().atMost(30, SECONDS).until(task::isDone); assertThat(task.isCompletedExceptionally()).isFalse(); assertThat(task.get()).isEqualTo(nextBlocks); for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); } }
@Test public void failsToImportInvalidBlock() { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final Block nextBlock = gen.block(); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); // Create task final PersistBlockTask<Void> task = PersistBlockTask.create( protocolSchedule, protocolContext, nextBlock, HeaderValidationMode.FULL, ethTasksTimer); final CompletableFuture<Block> result = task.run(); Awaitility.await().atMost(30, SECONDS).until(result::isDone); assertThat(result.isCompletedExceptionally()).isTrue(); assertThatThrownBy(result::get).hasCauseInstanceOf(InvalidBlockException.class); assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); }
@Test public void importsInvalidUnorderedBlocks() throws Exception { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(3); final List<Block> nextBlocks = Arrays.asList(gen.block(), gen.block()); // 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()).isTrue(); for (final Block nextBlock : nextBlocks) { assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); } }
@Test public void ignoresOldNewBlockAnnouncement() { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(10); final Block blockOne = blockchainUtil.getBlock(1); final Block oldBlock = gen.nextBlock(blockOne); // Sanity check assertThat(blockchain.contains(oldBlock.getHash())).isFalse(); final BlockPropagationManager<Void> propManager = spy(blockPropagationManager); propManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockMessage oldAnnouncement = NewBlockMessage.create(oldBlock, UInt256.ZERO); // Broadcast EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, oldAnnouncement); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); peer.respondWhile(responder, peer::hasOutstandingRequests); verify(propManager, times(0)).importOrSavePendingBlock(any()); assertThat(blockchain.contains(oldBlock.getHash())).isFalse(); }
@Test public void importsAnnouncedNewBlocks_aheadOfChainInOrder() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); final Block nextNextBlock = blockchainUtil.getBlock(3); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); assertThat(blockchain.contains(nextNextBlock.getHash())).isFalse(); blockPropagationManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockMessage nextAnnouncement = NewBlockMessage.create( nextBlock, fullBlockchain.getTotalDifficultyByHash(nextBlock.getHash()).get()); final NewBlockMessage nextNextAnnouncement = NewBlockMessage.create( nextNextBlock, fullBlockchain.getTotalDifficultyByHash(nextNextBlock.getHash()).get()); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); // Broadcast first message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); // Broadcast second message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextNextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); assertThat(blockchain.contains(nextNextBlock.getHash())).isTrue(); }
@Test public void importsAnnouncedNewBlocks_aheadOfChainOutOfOrder() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); final Block nextNextBlock = blockchainUtil.getBlock(3); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); assertThat(blockchain.contains(nextNextBlock.getHash())).isFalse(); blockPropagationManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockMessage nextAnnouncement = NewBlockMessage.create( nextBlock, fullBlockchain.getTotalDifficultyByHash(nextBlock.getHash()).get()); final NewBlockMessage nextNextAnnouncement = NewBlockMessage.create( nextNextBlock, fullBlockchain.getTotalDifficultyByHash(nextNextBlock.getHash()).get()); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); // Broadcast second message first EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextNextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); // Broadcast first message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); assertThat(blockchain.contains(nextNextBlock.getHash())).isTrue(); }
@Test public void ignoresFutureNewBlockAnnouncement() { blockchainUtil.importFirstBlocks(2); final Block futureBlock = blockchainUtil.getBlock(11); // Sanity check assertThat(blockchain.contains(futureBlock.getHash())).isFalse(); blockPropagationManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockMessage futureAnnouncement = NewBlockMessage.create( futureBlock, fullBlockchain.getTotalDifficultyByHash(futureBlock.getHash()).get()); // Broadcast EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, futureAnnouncement); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(futureBlock.getHash())).isFalse(); }
@Test public void ignoresOldNewBlockHashAnnouncement() { final BlockDataGenerator gen = new BlockDataGenerator(); blockchainUtil.importFirstBlocks(10); final Block blockOne = blockchainUtil.getBlock(1); final Block oldBlock = gen.nextBlock(blockOne); // Sanity check assertThat(blockchain.contains(oldBlock.getHash())).isFalse(); final BlockPropagationManager<Void> propManager = spy(blockPropagationManager); propManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockHashesMessage oldAnnouncement = NewBlockHashesMessage.create( Collections.singletonList( new NewBlockHash(oldBlock.getHash(), oldBlock.getHeader().getNumber()))); // Broadcast EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, oldAnnouncement); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); peer.respondWhile(responder, peer::hasOutstandingRequests); verify(propManager, times(0)).importOrSavePendingBlock(any()); assertThat(blockchain.contains(oldBlock.getHash())).isFalse(); }
@Test public void ignoresFutureNewBlockHashAnnouncement() { blockchainUtil.importFirstBlocks(2); final Block futureBlock = blockchainUtil.getBlock(11); // Sanity check assertThat(blockchain.contains(futureBlock.getHash())).isFalse(); blockPropagationManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockHashesMessage futureAnnouncement = NewBlockHashesMessage.create( Collections.singletonList( new NewBlockHash(futureBlock.getHash(), futureBlock.getHeader().getNumber()))); // Broadcast EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, futureAnnouncement); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(futureBlock.getHash())).isFalse(); }
@Test public void importsAnnouncedBlocks_aheadOfChainInOrder() { blockchainUtil.importFirstBlocks(2); final Block nextBlock = blockchainUtil.getBlock(2); final Block nextNextBlock = blockchainUtil.getBlock(3); // Sanity check assertThat(blockchain.contains(nextBlock.getHash())).isFalse(); assertThat(blockchain.contains(nextNextBlock.getHash())).isFalse(); blockPropagationManager.start(); // Setup peer and messages final RespondingEthPeer peer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager, 0); final NewBlockHashesMessage nextAnnouncement = NewBlockHashesMessage.create( Collections.singletonList( new NewBlockHash(nextBlock.getHash(), nextBlock.getHeader().getNumber()))); final NewBlockHashesMessage nextNextAnnouncement = NewBlockHashesMessage.create( Collections.singletonList( new NewBlockHash(nextNextBlock.getHash(), nextNextBlock.getHeader().getNumber()))); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); // Broadcast first message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); // Broadcast second message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, nextNextAnnouncement); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); assertThat(blockchain.contains(nextNextBlock.getHash())).isTrue(); }
@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()); }
@Test public void handlesDuplicateAnnouncements() { 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()); final Responder responder = RespondingEthPeer.blockchainResponder(fullBlockchain); // Broadcast first message EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, newBlock); peer.respondWhile(responder, peer::hasOutstandingRequests); // Broadcast duplicate EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, newBlockHash); peer.respondWhile(responder, peer::hasOutstandingRequests); // Broadcast duplicate EthProtocolManagerTestUtil.broadcastMessage(ethProtocolManager, peer, newBlock); peer.respondWhile(responder, peer::hasOutstandingRequests); assertThat(blockchain.contains(nextBlock.getHash())).isTrue(); verify(blockchain, times(1)).appendBlock(any(), any()); }