Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }