Esempio n. 1
0
        private bool IsDemandNeeded(
            BlockChain <T> blockChain,
            Func <IBlockExcerpt, bool> predicate,
            BlockDemand demand)
        {
            IComparer <IBlockExcerpt> canonComparer = blockChain.Policy.CanonicalChainComparer;
            BlockDemand?oldDemand = _blockDemands.ContainsKey(demand.Peer)
                ? _blockDemands[demand.Peer]
                : (BlockDemand?)null;

            bool needed;

            if (IsDemandStale(demand))
            {
                needed = false;
            }
            else if (predicate(demand))
            {
                if (oldDemand is { } old)
                {
                    needed = IsDemandStale(old) || canonComparer.Compare(old, demand) < 0;
                }
                else
                {
                    needed = true;
                }
            }
Esempio n. 2
0
 public void Add(
     BlockChain <T> blockChain,
     Func <IBlockExcerpt, bool> predicate,
     BlockDemand demand)
 {
     if (IsDemandNeeded(blockChain, predicate, demand))
     {
         _blockDemands[demand.Peer] = demand;
         Log.Debug(
             "BlockDemand #{Index} {BlockHash} from peer {Peer} added.",
             demand.Index,
             demand.Hash,
             demand.Peer);
     }
     else
     {
         Log.Debug(
             "BlockDemand #{Index} {BlockHash} from peer {Peer} ignored.",
             demand.Index,
             demand.Hash,
             demand.Peer);
     }
 }
Esempio n. 3
0
        private async Task ProcessBlockHeader(
            BlockHeaderMessage message,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!(message.Remote is BoundPeer peer))
            {
                _logger.Information(
                    "BlockHeaderMessage was sent from invalid peer " +
                    "{PeerAddress}; ignored.",
                    message.Remote.Address
                    );
                return;
            }

            if (!message.GenesisHash.Equals(BlockChain.Genesis.Hash))
            {
                _logger.Information(
                    "BlockHeaderMessage was sent from the peer " +
                    "{PeerAddress} with different genesis block {hash}; ignored.",
                    message.Remote.Address,
                    message.GenesisHash
                    );
                return;
            }

            BlockHeaderReceived.Set();
            BlockHeader header = message.Header;

            _logger.Debug(
                $"Received a {nameof(BlockHeader)} #{{BlockIndex}} {{BlockHash}}.",
                header.Index,
                ByteUtil.Hex(header.Hash)
                );

            try
            {
                header.Validate(DateTimeOffset.UtcNow);
            }
            catch (InvalidBlockException ibe)
            {
                _logger.Information(
                    ibe,
                    "A received header #{BlockIndex} {BlockHash} seems invalid; ignored.",
                    header.Index,
                    ByteUtil.Hex(header.Hash)
                    );
                return;
            }

            using (await _blockSyncMutex.LockAsync(cancellationToken))
            {
                if (IsDemandNeeded(header, peer))
                {
                    _logger.Debug(
                        "BlockDemand #{index} {blockHash} from {peer}.",
                        header.Index,
                        ByteUtil.Hex(header.Hash),
                        peer);
                    BlockDemand = new BlockDemand(header, peer, DateTimeOffset.UtcNow);
                }
                else
                {
                    _logger.Debug(
                        "No blocks are required " +
                        "(current: {Current}, demand: {Demand}, received: {Received});" +
                        $" {nameof(BlockHeaderMessage)} is ignored.",
                        BlockChain.Tip.Index,
                        BlockDemand?.Header.Index,
                        header.Index);
                }
            }
        }
Esempio n. 4
0
        private async Task ProcessFillBlocks(
            TimeSpan timeout,
            CancellationToken cancellationToken
            )
        {
            var sessionRandom = new Random();
            IComparer <BlockPerception> canonComparer = BlockChain.Policy.CanonicalChainComparer;

            while (!cancellationToken.IsCancellationRequested)
            {
                int sessionId = sessionRandom.Next();

                if (!(BlockDemand is { } blockDemand))
                {
                    await Task.Delay(1, cancellationToken);

                    continue;
                }

                BoundPeer peer = blockDemand.Peer;

                try
                {
                    if (canonComparer.Compare(
                            BlockChain.PerceiveBlock(BlockDemand?.Header),
                            BlockChain.PerceiveBlock(BlockChain.Tip)
                            ) <= 0)
                    {
                        using (await _blockSyncMutex.LockAsync(cancellationToken))
                        {
                            BlockDemand = null;
                            continue;
                        }
                    }

                    var          hash        = new BlockHash(blockDemand.Header.Hash);
                    const string startLogMsg =
                        "{SessionId}: Got a new " + nameof(BlockDemand) + " from {Peer}; started " +
                        "to fetch the block #{BlockIndex} {BlockHash}...";
                    _logger.Debug(startLogMsg, sessionId, peer, blockDemand.Header.Index, hash);
                    await SyncPreviousBlocksAsync(
                        blockChain : BlockChain,
                        peer : peer,
                        stop : hash,
                        progress : null,
                        timeout : timeout,
                        totalBlockCount : 0,
                        logSessionId : sessionId,
                        cancellationToken : cancellationToken
                        );

                    _logger.Debug(
                        "{SessionId}: Synced block(s) from {Peer}; broadcast them to neighbors...",
                        sessionId,
                        peer
                        );

                    // FIXME: Clean up events
                    BlockReceived.Set();
                    BlockAppended.Set();
                    BroadcastBlock(peer.Address, BlockChain.Tip);

                    ProcessFillBlocksFinished.Set();
                }
                catch (TimeoutException)
                {
                    const string msg =
                        "{SessionId}: Timeout occurred during " + nameof(ProcessFillBlocks) +
                        "() from {Peer}.";
                    _logger.Debug(msg, sessionId, peer);
                }
                catch (InvalidBlockIndexException ibie)
                {
                    const string msg =
                        "{SessionId}: " + nameof(InvalidBlockIndexException) + " occurred during " +
                        nameof(ProcessFillBlocks) + "() from {Peer}: {Exception}";
                    _logger.Warning(ibie, msg, sessionId, peer, ibie);
                }
                catch (Exception e)
                {
                    const string msg =
                        "{SessionId}: Unexpected exception occurred during " +
                        nameof(ProcessFillBlocks) + "() from {Peer}: {Exception}";
                    _logger.Error(e, msg, sessionId, peer, e);
                }
                finally
                {
                    using (await _blockSyncMutex.LockAsync(cancellationToken))
                    {
                        const string msg =
                            "{SessionId}: " + nameof(ProcessFillBlocks) + "() finished.";
                        _logger.Debug(msg, sessionId);
                        if (BlockDemand.Equals(blockDemand))
                        {
                            const string resetMsg =
                                "{SessionId}: Reset " + nameof(BlockDemand) + "...";
                            _logger.Debug(resetMsg, sessionId);
                            BlockDemand = null;
                        }
                    }
                }
            }
        }