Exemple #1
0
        private async Task <TransactionResult> ExecuteTransactionAsync(Transaction transaction)
        {
            var blockchainService = _serviceProvider.GetRequiredService <IBlockchainService>();
            var preBlock          = await blockchainService.GetBestChainLastBlockHeaderAsync();

            var miningService            = _serviceProvider.GetRequiredService <IMiningService>();
            var blockAttachService       = _serviceProvider.GetRequiredService <IBlockAttachService>();
            var blockTimeProvider        = _serviceProvider.GetRequiredService <IBlockTimeProvider>();
            var transactionResultService = _serviceProvider.GetRequiredService <ITransactionResultService>();

            var block = await miningService.MineAsync(
                new RequestMiningDto
            {
                PreviousBlockHash  = preBlock.GetHash(), PreviousBlockHeight = preBlock.Height,
                BlockExecutionTime = TimestampHelper.DurationFromMilliseconds(int.MaxValue)
            },
                new List <Transaction> {
                transaction
            },
                blockTimeProvider.GetBlockTime());

            await blockchainService.AddTransactionsAsync(new List <Transaction> {
                transaction
            });

            await blockchainService.AddBlockAsync(block);

            await blockAttachService.AttachBlockAsync(block);

            return(await transactionResultService.GetTransactionResultAsync(transaction.GetHash()));
        }
Exemple #2
0
        public async Task TriggerConsensusAsync(ChainContext chainContext)
        {
            var now = TimestampHelper.GetUtcNow();

            _blockTimeProvider.SetBlockTime(now);

            Logger.LogTrace($"Set block time to utc now: {now:hh:mm:ss.ffffff}. Trigger.");

            var triggerInformation = _triggerInformationProvider.GetTriggerInformationForConsensusCommand(new BytesValue());

            // Upload the consensus command.
            _consensusCommand = await _readerFactory.Create(chainContext)
                                .GetConsensusCommand.CallAsync(triggerInformation);

            Logger.LogDebug($"Updated consensus command: {_consensusCommand}");

            // Update next mining time, also block time of both getting consensus extra data and txs.
            _nextMiningTime =
                TimestampHelper.GetUtcNow().AddMilliseconds(_consensusCommand
                                                            .NextBlockMiningLeftMilliseconds);

            // Initial consensus scheduler.
            var blockMiningEventData = new ConsensusRequestMiningEventData(chainContext.BlockHash,
                                                                           chainContext.BlockHeight,
                                                                           _nextMiningTime,
                                                                           TimestampHelper.DurationFromMilliseconds(_consensusCommand.LimitMillisecondsOfMiningBlock));

            _consensusScheduler.CancelCurrentEvent();
            _consensusScheduler.NewEvent(_consensusCommand.NextBlockMiningLeftMilliseconds,
                                         blockMiningEventData);

            Logger.LogTrace($"Set next mining time to: {_nextMiningTime:hh:mm:ss.ffffff}");
        }
Exemple #3
0
        public Task BroadcastTransactionAsync(Transaction transaction)
        {
            var beforeEnqueue = TimestampHelper.GetUtcNow();

            _taskQueueManager.Enqueue(async() =>
            {
                var execTime = TimestampHelper.GetUtcNow();
                if (execTime > beforeEnqueue +
                    TimestampHelper.DurationFromMilliseconds(NetworkConstants.TransactionQueueJobTimeout))
                {
                    Logger.LogWarning($"Transaction too old: {execTime - beforeEnqueue}");
                    return;
                }

                foreach (var peer in _peerPool.GetPeers())
                {
                    try
                    {
                        await peer.SendTransactionAsync(transaction);
                    }
                    catch (NetworkException ex)
                    {
                        Logger.LogError(ex, "Error while sending transaction.");
                        await HandleNetworkException(peer, ex);
                    }
                }
            }, NetworkConstants.TransactionBroadcastQueueName);

            return(Task.CompletedTask);
        }
        private async Task <Block> ExecuteAsync(Transaction transaction, long previousBlockHeight, Hash previousBlockHash)
        {
            var transactionList = new List <Transaction>();

            if (transaction != null)
            {
                transactionList.Add(transaction);
            }
            var block = await _miningService.MineAsync(
                new RequestMiningDto
            {
                PreviousBlockHash  = previousBlockHash, PreviousBlockHeight = previousBlockHeight,
                BlockExecutionTime = TimestampHelper.DurationFromMilliseconds(int.MaxValue)
            },
                transactionList,
                DateTime.UtcNow.ToTimestamp());

            if (transaction != null)
            {
                await _blockchainService.AddTransactionsAsync(new List <Transaction> {
                    transaction
                });
            }
            await _blockchainService.AddBlockAsync(block);

            return(block);
        }
        private async Task <BlockExecutedSet> MineAsync(List <Transaction> txs, Timestamp blockTime, Hash preBlockHash,
                                                        long preBlockHeight)
        {
            var blockchainService  = Application.ServiceProvider.GetRequiredService <IBlockchainService>();
            var miningService      = Application.ServiceProvider.GetRequiredService <IMiningService>();
            var blockAttachService = Application.ServiceProvider.GetRequiredService <IBlockAttachService>();

            var executedBlockSet = await miningService.MineAsync(new RequestMiningDto
            {
                PreviousBlockHash     = preBlockHash,
                PreviousBlockHeight   = preBlockHeight,
                BlockExecutionTime    = TimestampHelper.DurationFromMilliseconds(int.MaxValue),
                TransactionCountLimit = int.MaxValue
            }, txs, blockTime ?? DateTime.UtcNow.ToTimestamp());

            var block = executedBlockSet.Block;

            await blockchainService.AddTransactionsAsync(txs);

            await blockchainService.AddBlockAsync(block);

            await blockAttachService.AttachBlockAsync(block);

            return(executedBlockSet);
        }
        public async Task <TransactionResult> ExecuteAsync(Transaction transaction)
        {
            var blockTimeProvider = _serviceProvider.GetRequiredService <IBlockTimeProvider>();
            var blockchainService = _serviceProvider.GetRequiredService <IBlockchainService>();
            var preBlock          = await blockchainService.GetBestChainLastBlockHeaderAsync();

            var miningService      = _serviceProvider.GetRequiredService <IMiningService>();
            var blockAttachService = _serviceProvider.GetRequiredService <IBlockAttachService>();

            var transactions = new List <Transaction> {
                transaction
            };
            var blockExecutedSet = await miningService.MineAsync(
                new RequestMiningDto
            {
                PreviousBlockHash     = preBlock.GetHash(), PreviousBlockHeight = preBlock.Height,
                BlockExecutionTime    = TimestampHelper.DurationFromMilliseconds(int.MaxValue),
                TransactionCountLimit = int.MaxValue
            }, transactions, blockTimeProvider.GetBlockTime());

            var block = blockExecutedSet.Block;

            await blockchainService.AddTransactionsAsync(transactions);

            await blockchainService.AddBlockAsync(block);

            await blockAttachService.AttachBlockAsync(block);

            return(blockExecutedSet.TransactionResultMap[transaction.GetHash()]);
        }
        public async Task Mine_Test()
        {
            var chain = await _blockchainService.GetChainAsync();

            Timestamp        blockTime;
            BlockExecutedSet miningResult;

            {
                blockTime    = TimestampHelper.GetUtcNow().AddSeconds(-4);
                miningResult = await _miningService.MineAsync(new RequestMiningDto
                {
                    BlockExecutionTime    = TimestampHelper.DurationFromSeconds(1),
                    PreviousBlockHash     = chain.BestChainHash,
                    PreviousBlockHeight   = chain.BestChainHeight,
                    TransactionCountLimit = 100
                },
                                                              _kernelTestHelper.GenerateTransactions(10), blockTime);
                await CheckMiningResultAsync(miningResult, blockTime, 0);
            }

            {
                blockTime    = TimestampHelper.GetUtcNow().AddSeconds(4);
                miningResult = await _miningService.MineAsync(new RequestMiningDto
                {
                    BlockExecutionTime    = TimestampHelper.DurationFromMilliseconds(int.MaxValue),
                    PreviousBlockHash     = chain.BestChainHash,
                    PreviousBlockHeight   = chain.BestChainHeight,
                    TransactionCountLimit = 100
                },
                                                              _kernelTestHelper.GenerateTransactions(10), blockTime);
                await CheckMiningResultAsync(miningResult, blockTime, 10);
            }

            {
                blockTime    = TimestampHelper.GetUtcNow();
                miningResult = await _miningService.MineAsync(new RequestMiningDto
                {
                    BlockExecutionTime    = TimestampHelper.DurationFromSeconds(4),
                    PreviousBlockHash     = chain.BestChainHash,
                    PreviousBlockHeight   = chain.BestChainHeight,
                    TransactionCountLimit = 100
                },
                                                              _kernelTestHelper.GenerateTransactions(10), blockTime);
                await CheckMiningResultAsync(miningResult, blockTime, 10);
            }

            {
                blockTime    = TimestampHelper.GetUtcNow();
                miningResult = await _miningService.MineAsync(new RequestMiningDto
                {
                    BlockExecutionTime    = TimestampHelper.DurationFromSeconds(4),
                    PreviousBlockHash     = chain.BestChainHash,
                    PreviousBlockHeight   = chain.BestChainHeight,
                    TransactionCountLimit = 5
                },
                                                              _kernelTestHelper.GenerateTransactions(10), blockTime);
                await CheckMiningResultAsync(miningResult, blockTime, 4);
            }
        }
Exemple #8
0
        private bool CheckAgeLimit(Timestamp enqueueTime, long ageLimit)
        {
            if (enqueueTime != null && TimestampHelper.GetUtcNow() >
                enqueueTime + TimestampHelper.DurationFromMilliseconds(ageLimit))
            {
                Logger.LogTrace($"Enqueue time is more then limit : {enqueueTime}");
                return(false);
            }

            return(true);
        }
        public async Task <HandshakeValidationResult> ValidateHandshakeAsync(Handshake handshake)
        {
            var pubkey = handshake.HandshakeData.Pubkey.ToHex();

            if (_networkOptions.AuthorizedPeers == AuthorizedPeers.Authorized &&
                !_networkOptions.AuthorizedKeys.Contains(pubkey))
            {
                return(HandshakeValidationResult.Unauthorized);
            }

            var chainId = _blockchainService.GetChainId();

            if (handshake.HandshakeData.ChainId != chainId)
            {
                Logger.LogWarning($"Chain is is incorrect: {handshake.HandshakeData.ChainId}.");
                return(HandshakeValidationResult.InvalidChainId);
            }

            if (handshake.HandshakeData.Version != KernelConstants.ProtocolVersion)
            {
                Logger.LogWarning($"Version is is incorrect: {handshake.HandshakeData.Version}.");
                return(HandshakeValidationResult.InvalidVersion);
            }

            var now = TimestampHelper.GetUtcNow();

            if (now > handshake.HandshakeData.Time +
                TimestampHelper.DurationFromMilliseconds(NetworkConstants.HandshakeTimeout))
            {
                Logger.LogWarning($"Handshake is expired: {handshake.HandshakeData.Time}, reference now: {now}.");
                return(HandshakeValidationResult.HandshakeTimeout);
            }

            byte[] handshakePubkey = handshake.HandshakeData.Pubkey.ToByteArray();

            var validData = CryptoHelper.VerifySignature(handshake.Signature.ToByteArray(),
                                                         Hash.FromMessage(handshake.HandshakeData).ToByteArray(), handshakePubkey);

            if (!validData)
            {
                Logger.LogWarning("Handshake signature is incorrect.");
                return(HandshakeValidationResult.InvalidSignature);
            }

            var nodePubKey = await _accountService.GetPublicKeyAsync();

            if (handshakePubkey.BytesEqual(nodePubKey))
            {
                Logger.LogWarning("Self connection detected.");
                return(HandshakeValidationResult.SelfConnection);
            }

            return(HandshakeValidationResult.Ok);
        }
        /// <summary>
        /// Basically update the consensus scheduler with latest consensus command.
        /// </summary>
        /// <param name="chainContext"></param>
        /// <returns></returns>
        public async Task TriggerConsensusAsync(ChainContext chainContext)
        {
            var now = TimestampHelper.GetUtcNow();

            _blockTimeProvider.SetBlockTime(now);

            Logger.LogDebug($"Set block time to utc now: {now.ToDateTime():hh:mm:ss.ffffff}. Trigger.");

            var triggerInformation =
                _triggerInformationProvider.GetTriggerInformationForConsensusCommand(new BytesValue());

            Logger.LogDebug($"Mining triggered, chain context: {chainContext.BlockHeight} - {chainContext.BlockHash}");

            // Upload the consensus command.
            var contractReaderContext =
                await _consensusReaderContextService.GetContractReaderContextAsync(chainContext);

            _consensusCommand = await _contractReaderFactory
                                .Create(contractReaderContext).GetConsensusCommand
                                .CallAsync(triggerInformation);

            if (_consensusCommand == null)
            {
                Logger.LogWarning("Consensus command is null.");
                return;
            }

            Logger.LogDebug($"Updated consensus command: {_consensusCommand}");

            // Update next mining time, also block time of both getting consensus extra data and txs.
            _nextMiningTime = _consensusCommand.ArrangedMiningTime;
            var leftMilliseconds = _consensusCommand.ArrangedMiningTime - TimestampHelper.GetUtcNow();

            leftMilliseconds = leftMilliseconds.Seconds > ConsensusConstants.MaximumLeftMillisecondsForNextBlock
                ? new Duration {
                Seconds = ConsensusConstants.MaximumLeftMillisecondsForNextBlock
            }
                : leftMilliseconds;

            // Update consensus scheduler.
            var blockMiningEventData = new ConsensusRequestMiningEventData(chainContext.BlockHash,
                                                                           chainContext.BlockHeight,
                                                                           _nextMiningTime,
                                                                           TimestampHelper.DurationFromMilliseconds(_consensusCommand.LimitMillisecondsOfMiningBlock),
                                                                           _consensusCommand.MiningDueTime);

            _consensusScheduler.CancelCurrentEvent();
            _consensusScheduler.NewEvent(leftMilliseconds.Milliseconds(), blockMiningEventData);

            Logger.LogDebug($"Set next mining time to: {_nextMiningTime.ToDateTime():hh:mm:ss.ffffff}");
        }
Exemple #11
0
        public Task BroadcastAnnounceAsync(BlockHeader blockHeader, bool hasFork)
        {
            var blockHash = blockHeader.GetHash();

            if (!TryAddKnownBlock(blockHeader))
            {
                return(Task.CompletedTask);
            }

            if (IsOldBlock(blockHeader))
            {
                return(Task.CompletedTask);
            }

            var announce = new BlockAnnouncement
            {
                BlockHash   = blockHash,
                BlockHeight = blockHeader.Height,
                HasFork     = hasFork
            };

            var beforeEnqueue = TimestampHelper.GetUtcNow();

            _taskQueueManager.Enqueue(async() =>
            {
                var execTime = TimestampHelper.GetUtcNow();
                if (execTime > beforeEnqueue +
                    TimestampHelper.DurationFromMilliseconds(NetworkConstants.AnnouncementQueueJobTimeout))
                {
                    Logger.LogWarning($"Announcement too old: {execTime - beforeEnqueue}");
                    return;
                }

                foreach (var peer in _peerPool.GetPeers())
                {
                    try
                    {
                        await peer.SendAnnouncementAsync(announce);
                    }
                    catch (NetworkException ex)
                    {
                        Logger.LogError(ex, $"Error while announcing to {peer}.");
                        await HandleNetworkException(peer, ex);
                    }
                }
            }, NetworkConstants.AnnouncementBroadcastQueueName);

            return(Task.CompletedTask);
        }
Exemple #12
0
        public async Task RequestMining_Test()
        {
            var chain = await _blockchainService.GetChainAsync();

            var request = new ConsensusRequestMiningDto
            {
                BlockTime           = TimestampHelper.GetUtcNow(),
                BlockExecutionTime  = TimestampHelper.DurationFromMilliseconds(500),
                MiningDueTime       = TimestampHelper.GetUtcNow().AddMilliseconds(499),
                PreviousBlockHash   = chain.BestChainHash,
                PreviousBlockHeight = chain.BestChainHeight
            };

            var block = await _miningRequestService.RequestMiningAsync(request);

            block.ShouldBeNull();

            request = new ConsensusRequestMiningDto
            {
                BlockTime           = TimestampHelper.GetUtcNow().AddMilliseconds(-501),
                BlockExecutionTime  = TimestampHelper.DurationFromMilliseconds(500),
                MiningDueTime       = TimestampHelper.GetUtcNow().AddMilliseconds(350),
                PreviousBlockHash   = chain.BestChainHash,
                PreviousBlockHeight = chain.BestChainHeight
            };
            block = await _miningRequestService.RequestMiningAsync(request);

            block.ShouldBeNull();

            request = new ConsensusRequestMiningDto
            {
                BlockTime           = TimestampHelper.GetUtcNow().AddMilliseconds(-400),
                BlockExecutionTime  = TimestampHelper.DurationFromMilliseconds(500),
                MiningDueTime       = TimestampHelper.GetUtcNow().AddMilliseconds(350),
                PreviousBlockHash   = chain.BestChainHash,
                PreviousBlockHeight = chain.BestChainHeight
            };
            block = await _miningRequestService.RequestMiningAsync(request);

            block.ShouldNotBeNull();
            block.Header.PreviousBlockHash.ShouldBe(chain.BestChainHash);
            block.Header.Height.ShouldBe(chain.BestChainHeight + 1);
            block.Header.Time.ShouldBe(request.BlockTime);
        }
Exemple #13
0
        public async Task <Block> MinedOneBlock(Hash previousBlockHash = null, long previousBlockHeight = 0)
        {
            if (previousBlockHash == null || previousBlockHeight == 0)
            {
                var chain = await _blockchainService.GetChainAsync();

                previousBlockHash   = chain.BestChainHash;
                previousBlockHeight = chain.BestChainHeight;
            }

            var block = await _minerService.MineAsync(previousBlockHash, previousBlockHeight,
                                                      TimestampHelper.GetUtcNow(), TimestampHelper.DurationFromMilliseconds(4000));

            await _blockchainService.AddBlockAsync(block);

            await _blockAttachService.AttachBlockAsync(block);

            return(block);
        }
Exemple #14
0
        /// <summary>
        /// Mine a block with given normal txs and system txs.
        /// Normal txs will use tx pool while system txs not.
        /// </summary>
        /// <param name="txs"></param>
        /// <returns></returns>
        public async Task <Block> MineAsync(List <Transaction> txs)
        {
            await AddTransactionsAsync(txs);

            var blockchainService = Application.ServiceProvider.GetRequiredService <IBlockchainService>();
            var preBlock          = await blockchainService.GetBestChainLastBlockHeaderAsync();

            var minerService       = Application.ServiceProvider.GetRequiredService <IMinerService>();
            var blockAttachService = Application.ServiceProvider.GetRequiredService <IBlockAttachService>();

            var block = await minerService.MineAsync(preBlock.GetHash(), preBlock.Height,
                                                     DateTime.UtcNow.ToTimestamp(), TimestampHelper.DurationFromMilliseconds(int.MaxValue));

            await blockchainService.AddBlockAsync(block);

            await blockAttachService.AttachBlockAsync(block);

            return(block);
        }
        public async Task ExecuteAsync(Transaction transaction)
        {
            var blockTimeProvider = _serviceProvider.GetRequiredService<IBlockTimeProvider>();
            var txHub = _serviceProvider.GetRequiredService<ITxHub>();
            await txHub.HandleTransactionsReceivedAsync(new TransactionsReceivedEvent
            {
                Transactions = new List<Transaction> {transaction}
            });
            var blockchainService = _serviceProvider.GetRequiredService<IBlockchainService>();
            var preBlock = await blockchainService.GetBestChainLastBlockHeaderAsync();
            var minerService = _serviceProvider.GetRequiredService<IMinerService>();
            var blockAttachService = _serviceProvider.GetRequiredService<IBlockAttachService>();

            var block = await minerService.MineAsync(preBlock.GetHash(), preBlock.Height,
                blockTimeProvider.GetBlockTime(), TimestampHelper.DurationFromMilliseconds(int.MaxValue));

            await blockchainService.AddBlockAsync(block);
            await blockAttachService.AttachBlockAsync(block);
        }
        public async Task DoHandshake_InvalidHandshake_Test()
        {
            AElfPeerEndpointHelper.TryParse(NetworkTestConstants.GoodPeerEndpoint, out var endpoint);

            var handshake = CreateHandshake();

            handshake.HandshakeData.ChainId = 100;
            var result = await _connectionService.DoHandshakeAsync(endpoint, handshake);

            result.Error.ShouldBe(HandshakeError.ChainMismatch);

            handshake = CreateHandshake();
            handshake.HandshakeData.Version = 100;
            result = await _connectionService.DoHandshakeAsync(endpoint, handshake);

            result.Error.ShouldBe(HandshakeError.ProtocolMismatch);

            handshake = CreateHandshake();
            handshake.HandshakeData.Time = handshake.HandshakeData.Time -
                                           TimestampHelper.DurationFromMilliseconds(
                NetworkConstants.HandshakeTimeout + 1000);
            result = await _connectionService.DoHandshakeAsync(endpoint, handshake);

            result.Error.ShouldBe(HandshakeError.SignatureTimeout);

            handshake = CreateHandshake();
            handshake.HandshakeData.Pubkey = ByteString.CopyFrom(CryptoHelper.GenerateKeyPair().PublicKey);
            result = await _connectionService.DoHandshakeAsync(endpoint, handshake);

            result.Error.ShouldBe(HandshakeError.WrongSignature);

            handshake = await _handshakeProvider.GetHandshakeAsync();

            result = await _connectionService.DoHandshakeAsync(endpoint, handshake);

            result.Error.ShouldBe(HandshakeError.ConnectionRefused);
        }
Exemple #17
0
        private async Task <Block> MineAsync(List <Transaction> txs, Timestamp blockTime, Hash preBlockHash,
                                             long preBlockHeight)
        {
            await AddTransactionsAsync(txs);

            var blockchainService  = Application.ServiceProvider.GetRequiredService <IBlockchainService>();
            var minerService       = Application.ServiceProvider.GetRequiredService <IMinerService>();
            var blockAttachService = Application.ServiceProvider.GetRequiredService <IBlockAttachService>();

            var block = await minerService.MineAsync(preBlockHash, preBlockHeight,
                                                     blockTime ?? DateTime.UtcNow.ToTimestamp(), TimestampHelper.DurationFromMilliseconds(int.MaxValue));

            await blockchainService.AddBlockAsync(block);

            await blockAttachService.AttachBlockAsync(block);

            return(block);
        }
        public async Task MineWithTxHubAsync()
        {
            var txCount        = 0;
            var preBlockHash   = _chain.BestChainHash;
            var preBlockHeight = _chain.BestChainHeight;

            while (txCount < TransactionCount)
            {
                var blockExecutedSet = await _minerService.MineAsync(preBlockHash, preBlockHeight,
                                                                     TimestampHelper.GetUtcNow(), TimestampHelper.DurationFromMilliseconds(4000));

                txCount += blockExecutedSet.TransactionIds.Count();
                _transactionIdList.AddRange(blockExecutedSet.TransactionIds.ToList());
                await BlockchainService.SetBestChainAsync(_chain, preBlockHeight, preBlockHash);

                await TransactionPoolService.CleanByTransactionIdsAsync(blockExecutedSet.TransactionIds);

                await TransactionPoolService.UpdateTransactionPoolByBestChainAsync(preBlockHash, preBlockHeight);
            }
        }
Exemple #19
0
        public void DurationFromMilliseconds_Test()
        {
            var result = TimestampHelper.DurationFromMilliseconds(1000);

            result.Seconds.ShouldBe(1);
        }
        internal async Task DoReconnectionJobAsync()
        {
            CheckNtpClockDrift();

            await _networkService.CheckPeersHealthAsync();

            var peersToConnect = _reconnectionService.GetPeersReadyForReconnection(TimestampHelper.GetUtcNow());

            if (peersToConnect.Count <= 0)
            {
                return;
            }

            foreach (var peerToConnect in peersToConnect)
            {
                string peerEndpoint = peerToConnect.Endpoint;
                if (!AElfPeerEndpointHelper.TryParse(peerEndpoint, out var parsed))
                {
                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogWarning($"Invalid {peerEndpoint}.");
                    }

                    continue;
                }

                // check that we haven't already reconnected to this node
                if (_peerPool.FindPeerByEndpoint(parsed) != null)
                {
                    Logger.LogDebug($"Peer {peerEndpoint} already in the pool, no need to reconnect.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find to {peerEndpoint}.");
                    }

                    continue;
                }

                Logger.LogDebug($"Starting reconnection to {peerToConnect.Endpoint}.");

                var connected = false;

                try
                {
                    connected = await _networkService.AddPeerAsync(peerEndpoint);
                }
                catch (Exception ex)
                {
                    // down the stack the AddPeerAsync rethrows any exception,
                    // in order to continue this job, Exception has to be catched for now.
                    Logger.LogInformation(ex, $"Could not re-connect to {peerEndpoint}.");
                }

                if (connected)
                {
                    Logger.LogDebug($"Reconnection to {peerEndpoint} succeeded.");

                    if (!_reconnectionService.CancelReconnection(peerEndpoint))
                    {
                        Logger.LogDebug($"Could not find {peerEndpoint}.");
                    }
                }
                else
                {
                    var timeExtension = _networkOptions.PeerReconnectionPeriod * (int)Math.Pow(2, ++peerToConnect.RetryCount);
                    peerToConnect.NextAttempt = TimestampHelper.GetUtcNow().AddMilliseconds(timeExtension);

                    // if the option is set, verify that the next attempt does not exceed
                    // the maximum reconnection time.
                    if (_networkOptions.MaximumReconnectionTime != 0)
                    {
                        var maxReconnectionDate = peerToConnect.DisconnectionTime +
                                                  TimestampHelper.DurationFromMilliseconds(_networkOptions.MaximumReconnectionTime);

                        if (peerToConnect.NextAttempt > maxReconnectionDate)
                        {
                            _reconnectionService.CancelReconnection(peerEndpoint);
                            Logger.LogDebug($"Maximum reconnection time reached {peerEndpoint}, " +
                                            $"next was {peerToConnect.NextAttempt}.");

                            continue;
                        }
                    }

                    Logger.LogDebug($"Could not connect to {peerEndpoint}, next attempt {peerToConnect.NextAttempt}, " +
                                    $"current retries {peerToConnect.RetryCount}.");
                }
            }

            void CheckNtpClockDrift()
            {
                try
                {
                    _networkService.CheckNtpDrift();
                }
                catch (Exception)
                {
                    // swallow any exception, we are not interested in anything else than valid checks.
                }
            }
        }