private static HeadersSyncBatch BuildRightFiller(HeadersSyncBatch batch, int rightFillerSize) { HeadersSyncBatch rightFiller = new HeadersSyncBatch(); rightFiller.StartNumber = batch.EndNumber - rightFillerSize + 1; rightFiller.RequestSize = rightFillerSize; rightFiller.MinNumber = batch.MinNumber; return(rightFiller); }
private static HeadersSyncBatch BuildLeftFiller(HeadersSyncBatch batch, int leftFillerSize) { HeadersSyncBatch leftFiller = new HeadersSyncBatch(); leftFiller.StartNumber = batch.StartNumber; leftFiller.RequestSize = leftFillerSize; leftFiller.MinNumber = batch.MinNumber; return(leftFiller); }
private HeadersSyncBatch BuildNewBatch() { HeadersSyncBatch batch = new HeadersSyncBatch(); batch.MinNumber = _lowestRequestedHeaderNumber - 1; batch.StartNumber = Math.Max(0, _lowestRequestedHeaderNumber - _headersRequestSize); batch.RequestSize = (int)Math.Min(_lowestRequestedHeaderNumber, _headersRequestSize); _lowestRequestedHeaderNumber = batch.StartNumber; return(batch); }
private static HeadersSyncBatch BuildDependentBatch(HeadersSyncBatch batch, long addedLast, long addedEarliest) { HeadersSyncBatch dependentBatch = new HeadersSyncBatch(); dependentBatch.StartNumber = batch.StartNumber; dependentBatch.RequestSize = (int)(addedLast - addedEarliest + 1); dependentBatch.MinNumber = batch.MinNumber; dependentBatch.Response = batch.Response .Skip((int)(addedEarliest - batch.StartNumber)) .Take((int)(addedLast - addedEarliest + 1)).ToArray(); dependentBatch.ResponseSourcePeer = batch.ResponseSourcePeer; return(dependentBatch); }
private int InsertHeaders(HeadersSyncBatch batch) { if (batch.Response == null) { return(0); } if (batch.Response.Length > batch.RequestSize) { if (_logger.IsDebug) { _logger.Debug($"Peer sent too long response ({batch.Response.Length}) to {batch}"); } if (batch.ResponseSourcePeer != null) { _syncPeerPool.ReportBreachOfProtocol( batch.ResponseSourcePeer, $"response too long ({batch.Response.Length})"); } _pending.Enqueue(batch); return(0); } long addedLast = batch.StartNumber - 1; long addedEarliest = batch.EndNumber + 1; int skippedAtTheEnd = 0; for (int i = batch.Response.Length - 1; i >= 0; i--) { BlockHeader header = batch.Response[i]; if (header == null) { skippedAtTheEnd++; continue; } if (header.Number != batch.StartNumber + i) { if (batch.ResponseSourcePeer != null) { _syncPeerPool.ReportBreachOfProtocol( batch.ResponseSourcePeer, "inconsistent headers batch"); } break; } bool isFirst = i == batch.Response.Length - 1 - skippedAtTheEnd; if (isFirst) { BlockHeader lowestInserted = _blockTree.LowestInsertedHeader; // response does not carry expected data if (header.Number == lowestInserted?.Number && header.Hash != lowestInserted?.Hash) { if (batch.ResponseSourcePeer != null) { if (_logger.IsDebug) { _logger.Debug($"{batch} - reporting INVALID hash"); } _syncPeerPool.ReportBreachOfProtocol(batch.ResponseSourcePeer, "first hash inconsistent with request"); } break; } // response needs to be cached until predecessors arrive if (header.Hash != _nextHeaderHash) { if (header.Number == (_blockTree.LowestInsertedHeader?.Number ?? _pivotNumber + 1) - 1) { if (_logger.IsDebug) { _logger.Debug($"{batch} - ended up IGNORED - different branch - number {header.Number} was {header.Hash} while expected {_nextHeaderHash}"); } if (batch.ResponseSourcePeer != null) { _syncPeerPool.ReportBreachOfProtocol( batch.ResponseSourcePeer, "headers - different branch"); } break; } if (header.Number == _blockTree.LowestInsertedHeader?.Number) { if (_logger.IsDebug) { _logger.Debug($"{batch} - ended up IGNORED - different branch"); } if (batch.ResponseSourcePeer != null) { _syncPeerPool.ReportBreachOfProtocol( batch.ResponseSourcePeer, "headers - different branch"); } break; } if (_dependencies.ContainsKey(header.Number)) { _pending.Enqueue(batch); throw new InvalidOperationException($"Only one header dependency expected ({batch})"); } for (int j = 0; j < batch.Response.Length; j++) { BlockHeader current = batch.Response[j]; if (batch.Response[j] != null) { addedEarliest = Math.Min(addedEarliest, current.Number); addedLast = Math.Max(addedLast, current.Number); } else { break; } } HeadersSyncBatch dependentBatch = BuildDependentBatch(batch, addedLast, addedEarliest); _dependencies[header.Number] = dependentBatch; if (_logger.IsDebug) { _logger.Debug($"{batch} -> DEPENDENCY {dependentBatch}"); } // but we cannot do anything with it yet break; } } else { if (header.Hash != batch.Response[i + 1]?.ParentHash) { if (batch.ResponseSourcePeer != null) { if (_logger.IsDebug) { _logger.Debug($"{batch} - reporting INVALID inconsistent"); } _syncPeerPool.ReportBreachOfProtocol(batch.ResponseSourcePeer, "headers - response not matching request"); } break; } } header.TotalDifficulty = _nextHeaderDiff; AddBlockResult addBlockResult = InsertHeader(header); if (addBlockResult == AddBlockResult.InvalidBlock) { if (batch.ResponseSourcePeer != null) { if (_logger.IsDebug) { _logger.Debug($"{batch} - reporting INVALID bad block"); } _syncPeerPool.ReportBreachOfProtocol(batch.ResponseSourcePeer, $"invalid header {header.ToString(BlockHeader.Format.Short)}"); } break; } addedEarliest = Math.Min(addedEarliest, header.Number); addedLast = Math.Max(addedLast, header.Number); } int added = (int)(addedLast - addedEarliest + 1); int leftFillerSize = (int)(addedEarliest - batch.StartNumber); int rightFillerSize = (int)(batch.EndNumber - addedLast); if (added + leftFillerSize + rightFillerSize != batch.RequestSize) { throw new Exception($"Added {added} + left {leftFillerSize} + right {rightFillerSize} != request size {batch.RequestSize} in {batch}"); } added = Math.Max(0, added); if (added < batch.RequestSize) { if (added <= 0) { batch.Response = null; _pending.Enqueue(batch); } else { if (leftFillerSize > 0) { HeadersSyncBatch leftFiller = BuildLeftFiller(batch, leftFillerSize); _pending.Enqueue(leftFiller); if (_logger.IsDebug) { _logger.Debug($"{batch} -> FILLER {leftFiller}"); } } if (rightFillerSize > 0) { HeadersSyncBatch rightFiller = BuildRightFiller(batch, rightFillerSize); _pending.Enqueue(rightFiller); if (_logger.IsDebug) { _logger.Debug($"{batch} -> FILLER {rightFiller}"); } } } } if (added == 0) { if (batch.ResponseSourcePeer != null) { if (_logger.IsDebug) { _logger.Debug($"{batch} - reporting no progress"); } _syncPeerPool.ReportNoSyncProgress(batch.ResponseSourcePeer, AllocationContexts.Headers); } } if (_blockTree.LowestInsertedHeader != null) { _syncReport.FastBlocksHeaders.Update(_pivotNumber - _blockTree.LowestInsertedHeader.Number + 1); } if (_logger.IsDebug) { _logger.Debug($"LOWEST_INSERTED {_blockTree.LowestInsertedHeader?.Number} | HANDLED {batch}"); } _syncReport.HeadersInQueue.Update(HeadersInQueue); return(added); }