@ -12,12 +12,29 @@
* /
* /
package tech.pegasys.pantheon.ethereum.eth.sync.tasks ;
package tech.pegasys.pantheon.ethereum.eth.sync.tasks ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThatThrownBy ;
import tech.pegasys.pantheon.ethereum.core.BlockHeader ;
import tech.pegasys.pantheon.ethereum.core.BlockHeader ;
import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManagerTestUtil ;
import tech.pegasys.pantheon.ethereum.eth.manager.EthTask ;
import tech.pegasys.pantheon.ethereum.eth.manager.EthTask ;
import tech.pegasys.pantheon.ethereum.eth.manager.RespondingEthPeer ;
import tech.pegasys.pantheon.ethereum.eth.manager.RespondingEthPeer.Responder ;
import tech.pegasys.pantheon.ethereum.eth.manager.ethtaskutils.RetryingMessageTaskTest ;
import tech.pegasys.pantheon.ethereum.eth.manager.ethtaskutils.RetryingMessageTaskTest ;
import tech.pegasys.pantheon.ethereum.eth.manager.exceptions.MaxRetriesReachedException ;
import tech.pegasys.pantheon.ethereum.eth.messages.BlockHeadersMessage ;
import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62 ;
import tech.pegasys.pantheon.ethereum.p2p.api.MessageData ;
import java.util.ArrayList ;
import java.util.ArrayList ;
import java.util.Collections ;
import java.util.List ;
import java.util.List ;
import java.util.Optional ;
import java.util.concurrent.CompletableFuture ;
import java.util.stream.Collectors ;
import com.google.common.collect.Streams ;
import org.junit.Test ;
public class DownloadHeaderSequenceTaskTest extends RetryingMessageTaskTest < List < BlockHeader > > {
public class DownloadHeaderSequenceTaskTest extends RetryingMessageTaskTest < List < BlockHeader > > {
@ -44,4 +61,62 @@ public class DownloadHeaderSequenceTaskTest extends RetryingMessageTaskTest<List
requestedData . size ( ) ,
requestedData . size ( ) ,
maxRetries ) ;
maxRetries ) ;
}
}
@Test
public void failsWhenPeerReturnsOnlyReferenceHeader ( ) {
final RespondingEthPeer respondingPeer =
EthProtocolManagerTestUtil . createPeer ( ethProtocolManager ) ;
// Execute task and wait for response
BlockHeader referenceHeader = blockchain . getChainHeadHeader ( ) ;
final EthTask < List < BlockHeader > > task =
DownloadHeaderSequenceTask . endingAtHeader (
protocolSchedule , protocolContext , ethContext , referenceHeader , 10 , maxRetries ) ;
final CompletableFuture < List < BlockHeader > > future = task . run ( ) ;
// Respond with only the reference header
final Responder responder =
( cap , message ) - >
Optional . of ( BlockHeadersMessage . create ( Collections . singletonList ( referenceHeader ) ) ) ;
respondingPeer . respondWhile ( responder , ( ) - > ! future . isDone ( ) ) ;
assertThat ( future . isDone ( ) ) . isTrue ( ) ;
assertThat ( future . isCompletedExceptionally ( ) ) . isTrue ( ) ;
assertThatThrownBy ( future : : get ) . hasCauseInstanceOf ( MaxRetriesReachedException . class ) ;
}
@Test
public void failsWhenPeerReturnsOnlySubsetOfHeaders ( ) {
final RespondingEthPeer respondingPeer =
EthProtocolManagerTestUtil . createPeer ( ethProtocolManager ) ;
// Execute task and wait for response
BlockHeader referenceHeader = blockchain . getChainHeadHeader ( ) ;
final EthTask < List < BlockHeader > > task =
DownloadHeaderSequenceTask . endingAtHeader (
protocolSchedule , protocolContext , ethContext , referenceHeader , 10 , maxRetries ) ;
final CompletableFuture < List < BlockHeader > > future = task . run ( ) ;
// Filter response to include only reference header and previous header
final Responder fullResponder = RespondingEthPeer . blockchainResponder ( blockchain ) ;
final Responder responder =
( cap , message ) - > {
Optional < MessageData > fullResponse = fullResponder . respond ( cap , message ) ;
if ( ! fullResponse . isPresent ( ) | | message . getCode ( ) ! = EthPV62 . GET_BLOCK_HEADERS ) {
return fullResponse ;
}
BlockHeadersMessage headersMessage = BlockHeadersMessage . readFrom ( fullResponse . get ( ) ) ;
// Filter for a subset of headers
List < BlockHeader > headerSubset =
Streams . stream ( headersMessage . getHeaders ( protocolSchedule ) )
. filter ( h - > h . getNumber ( ) > = referenceHeader . getNumber ( ) - 1L )
. collect ( Collectors . toList ( ) ) ;
return Optional . of ( BlockHeadersMessage . create ( headerSubset ) ) ;
} ;
respondingPeer . respondTimes ( responder , 100 ) ;
assertThat ( future . isDone ( ) ) . isTrue ( ) ;
assertThat ( future . isCompletedExceptionally ( ) ) . isTrue ( ) ;
assertThatThrownBy ( future : : get ) . hasCauseInstanceOf ( MaxRetriesReachedException . class ) ;
}
}
}