Coverage Summary for Class: DownloadingHeadersSyncState (co.rsk.net.sync)

Class Class, % Method, % Line, %
DownloadingHeadersSyncState 0% (0/1) 0% (0/7) 0% (0/53)


1 package co.rsk.net.sync; 2  3 import co.rsk.core.bc.ConsensusValidationMainchainView; 4 import co.rsk.crypto.Keccak256; 5 import co.rsk.net.Peer; 6 import co.rsk.scoring.EventType; 7 import co.rsk.validators.BlockHeaderValidationRule; 8 import com.google.common.annotations.VisibleForTesting; 9 import org.ethereum.core.BlockHeader; 10 import org.ethereum.core.BlockIdentifier; 11 import org.ethereum.rpc.TypeConverter; 12 import org.ethereum.util.ByteUtil; 13 import org.ethereum.validator.DependentBlockHeaderRule; 14  15 import java.util.*; 16 import java.util.concurrent.ConcurrentHashMap; 17  18 public class DownloadingHeadersSyncState extends BaseSyncState { 19  20  private final Map<Peer, List<BlockIdentifier>> skeletons; 21  private final List<Deque<BlockHeader>> pendingHeaders; 22  private final ChunksDownloadHelper chunksDownloadHelper; 23  private final DependentBlockHeaderRule blockParentValidationRule; 24  private final BlockHeaderValidationRule blockHeaderValidationRule; 25  private final Peer selectedPeer; 26  private Map<Keccak256, BlockHeader> pendingHeadersByHash; 27  28  public DownloadingHeadersSyncState( 29  SyncConfiguration syncConfiguration, 30  SyncEventsHandler syncEventsHandler, 31  ConsensusValidationMainchainView mainchainView, 32  DependentBlockHeaderRule blockParentValidationRule, 33  BlockHeaderValidationRule blockHeaderValidationRule, 34  Peer peer, 35  Map<Peer, List<BlockIdentifier>> skeletons, 36  long connectionPoint) { 37  super(syncEventsHandler, syncConfiguration); 38  this.blockParentValidationRule = blockParentValidationRule; 39  this.blockHeaderValidationRule = blockHeaderValidationRule; 40  this.selectedPeer = peer; 41  this.pendingHeaders = new ArrayList<>(); 42  this.skeletons = skeletons; 43  this.chunksDownloadHelper = new ChunksDownloadHelper( 44  syncConfiguration, 45  skeletons.get(selectedPeer), 46  connectionPoint); 47  this.pendingHeadersByHash = new ConcurrentHashMap<>(); 48  mainchainView.setPendingHeaders(pendingHeadersByHash); 49  } 50  51  @Override 52  public void newBlockHeaders(List<BlockHeader> chunk) { 53  Optional<ChunkDescriptor> currentChunkOpt = chunksDownloadHelper.getCurrentChunk(); 54  if (!currentChunkOpt.isPresent()) { 55  syncEventsHandler.onSyncIssue( 56  "Current chunk not present. Node {}", 57  selectedPeer.getPeerNodeID()); 58  return; 59  } 60  ChunkDescriptor currentChunk = currentChunkOpt.get(); 61  if (chunk.size() != currentChunk.getCount() 62  || !ByteUtil.fastEquals(chunk.get(0).getHash().getBytes(), currentChunk.getHash())) { 63  syncEventsHandler.onErrorSyncing( 64  selectedPeer.getPeerNodeID(), 65  "Invalid chunk received from node {} {}", EventType.INVALID_MESSAGE, 66  selectedPeer.getPeerNodeID(), 67  TypeConverter.toUnformattedJsonHex(currentChunk.getHash())); 68  return; 69  } 70  71  Deque<BlockHeader> headers = new ArrayDeque<>(); 72  // the headers come ordered by block number desc 73  // we start adding the first parent header 74  BlockHeader headerToAdd = chunk.get(chunk.size() - 1); 75  headers.add(headerToAdd); 76  pendingHeadersByHash.put(headerToAdd.getHash(), headerToAdd); 77  78  for (int k = 1; k < chunk.size(); ++k) { 79  BlockHeader parentHeader = chunk.get(chunk.size() - k); 80  BlockHeader header = chunk.get(chunk.size() - k - 1); 81  82  if (!blockHeaderIsValid(header, parentHeader)) { 83  syncEventsHandler.onErrorSyncing( 84  selectedPeer.getPeerNodeID(), 85  "Invalid header received from node {} {} {}", EventType.INVALID_HEADER, 86  header.getNumber(), header.getPrintableHash()); 87  return; 88  } 89  90  headers.add(header); 91  pendingHeadersByHash.put(header.getHash(), header); 92  } 93  94  pendingHeaders.add(headers); 95  96  if (!chunksDownloadHelper.hasNextChunk()) { 97  // Finished verifying headers 98  syncEventsHandler.startDownloadingBodies(pendingHeaders, skeletons, selectedPeer); 99  return; 100  } 101  102  resetTimeElapsed(); 103  trySendRequest(); 104  } 105  106  @Override 107  public void onEnter() { 108  trySendRequest(); 109  } 110  111  @VisibleForTesting 112  public List<BlockIdentifier> getSkeleton() { 113  return chunksDownloadHelper.getSkeleton(); 114  } 115  116  private void trySendRequest() { 117  syncEventsHandler.sendBlockHeadersRequest(selectedPeer, chunksDownloadHelper.getNextChunk()); 118  } 119  120  @Override 121  protected void onMessageTimeOut() { 122  syncEventsHandler.onErrorSyncing( 123  selectedPeer.getPeerNodeID(), 124  "Timeout waiting requests {}", 125  EventType.TIMEOUT_MESSAGE, 126  this.getClass(), 127  selectedPeer.getPeerNodeID()); 128  } 129  130  private boolean blockHeaderIsValid(BlockHeader header, BlockHeader parentHeader) { 131  if (!parentHeader.getHash().equals(header.getParentHash())) { 132  return false; 133  } 134  135  if (header.getNumber() != parentHeader.getNumber() + 1) { 136  return false; 137  } 138  139  if (!blockHeaderValidationRule.isValid(header)) { 140  return false; 141  } 142  143  return blockParentValidationRule.validate(header, parentHeader); 144  } 145 }