예제 #1
0
        public Task ProcessAnnouncement(BlockAnnouncement announcement, ServerCallContext context)
        {
            if (announcement?.BlockHash == null)
            {
                Logger.LogWarning($"Received null announcement or header from {context.GetPeerInfo()}.");
                return(Task.CompletedTask);
            }

            Logger.LogDebug(
                $"Received announce, block hash: {announcement.BlockHash}, block height: {announcement.BlockHeight} from {context.GetPeerInfo()}.");

            var peer = _connectionService.GetPeerByPubkey(context.GetPublicKey());

            if (peer == null)
            {
                // if peer already removed, drop.
                return(Task.CompletedTask);
            }

            if (!peer.TryAddKnownBlock(announcement.BlockHash))
            {
                return(Task.CompletedTask);
            }

            if (peer.SyncState != SyncState.Finished)
            {
                peer.SyncState = SyncState.Finished;
            }

            _ = EventBus.PublishAsync(new AnnouncementReceivedEventData(announcement, context.GetPublicKey()));

            return(Task.CompletedTask);
        }
예제 #2
0
        public void Peer_AddKnowBlock_Test()
        {
            //fork clean hash
            var announcement = new BlockAnnouncement
            {
                HasFork = true
            };

            _grpcPeer.AddKnowBlock(announcement);
            _grpcPeer.RecentBlockHeightAndHashMappings.Count().ShouldBe(0);

            for (var i = 0; i < 10; i++)
            {
                _grpcPeer.AddKnowBlock(new BlockAnnouncement
                {
                    BlockHash   = Hash.FromString($"height-{i+1}"),
                    BlockHeight = i + 1,
                    HasFork     = false
                });
                _grpcPeer.RecentBlockHeightAndHashMappings.Count().ShouldBe(i + 1);
            }

            //over max value
            _grpcPeer.AddKnowBlock(new BlockAnnouncement
            {
                BlockHash   = Hash.FromString($"random-hash"),
                BlockHeight = 20,
                HasFork     = false
            });
            _grpcPeer.RecentBlockHeightAndHashMappings.Count().ShouldBe(10);
        }
        public async Task HandleAnnounceReceiveEventAsync_IrreversibleBlockIndex_IsNull()
        {
            var an               = new BlockAnnouncement();
            var sendKey          = string.Empty;
            var announcementData = new AnnouncementReceivedEventData(an, sendKey);

            await _dpoSAnnouncementReceivedEventDataHandler.HandleEventAsync(announcementData);
        }
예제 #4
0
        public void EnqueueAnnouncement(BlockAnnouncement announcement, Action <NetworkException> sendCallback)
        {
            if (!IsReady)
            {
                throw new NetworkException($"Dropping announcement, peer is not ready - {this}.",
                                           NetworkExceptionType.NotConnected);
            }

            _sendAnnouncementJobs.Post(new StreamJob {
                BlockAnnouncement = announcement, SendCallback = sendCallback
            });
        }
        public async Task HandleAnnounceReceiveEventAsync_IrreversibleBlockIndex_SureAmountEnough()
        {
            var block = await GenerateNewBlockAndAnnouncementToPeers(3);

            var an = new BlockAnnouncement
            {
                BlockHash   = block.GetHash(),
                BlockHeight = block.Height
            };
            var sendKey          = CryptoHelper.GenerateKeyPair().PublicKey.ToHex();
            var announcementData = new AnnouncementReceivedEventData(an, sendKey);

            await _dpoSAnnouncementReceivedEventDataHandler.HandleEventAsync(announcementData);
        }
예제 #6
0
        /// <summary>
        /// This method is called when a peer wants to broadcast an announcement.
        /// </summary>
        public override async Task <VoidReply> SendAnnouncement(BlockAnnouncement an, ServerCallContext context)
        {
            try
            {
                await ProcessAnnouncement(an, context);
            }
            catch (Exception e)
            {
                Logger.LogError(e, $"Process announcement error: {context.GetPeerInfo()}");
                throw;
            }

            return(new VoidReply());
        }
예제 #7
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);
        }
예제 #8
0
        public async Task HandleEventAsync(PeerConnectedEventData eventData)
        {
            Logger.LogDebug($"Peer connection event {eventData.NodeInfo}");

            await _peerDiscoveryService.AddNodeAsync(eventData.NodeInfo);

            var blockAnnouncement = new BlockAnnouncement {
                BlockHash   = eventData.BestChainHash,
                BlockHeight = eventData.BestChainHeight
            };

            var announcement = new AnnouncementReceivedEventData(blockAnnouncement, eventData.NodeInfo.Pubkey.ToHex());

            await LocalEventBus.PublishAsync(announcement);
        }
예제 #9
0
        public Task <bool> ValidateAnnouncementBeforeSyncAsync(Chain chain, BlockAnnouncement blockAnnouncement, string senderPubKey)
        {
            if (!TryCacheNewAnnouncement(blockAnnouncement.BlockHash, blockAnnouncement.BlockHeight, senderPubKey))
            {
                return(Task.FromResult(false));
            }

            if (blockAnnouncement.BlockHeight <= chain.LastIrreversibleBlockHeight)
            {
                Logger.LogWarning(
                    $"Receive lower header {{ hash: {blockAnnouncement.BlockHash}, height: {blockAnnouncement.BlockHeight} }} ignore.");
                return(Task.FromResult(false));
            }

            return(Task.FromResult(true));
        }
        public async Task ValidateAnnouncement_LessThenLIBHeight()
        {
            var chain = await _blockchainService.GetChainAsync();

            var blockAnnouncement = new BlockAnnouncement
            {
                BlockHash   = Hash.FromString("SyncBlockHash"),
                BlockHeight = chain.LastIrreversibleBlockHeight
            };

            var validateResult =
                await _blockSyncValidationService.ValidateAnnouncementAsync(chain, blockAnnouncement,
                                                                            GetEncodedPubKeyString());

            validateResult.ShouldBeFalse();
        }
예제 #11
0
        public async Task Announce_ShouldAddToBlockCache()
        {
            var peer     = _peerPool.GetPeers(true).First();
            var pubkey   = peer.Info.Pubkey;
            var metadata = new Metadata {
                { GrpcConstants.PubkeyMetadataKey, pubkey }
            };

            Hash hash         = Hash.FromRawBytes(new byte[] { 3, 6, 9 });
            var  announcement = new BlockAnnouncement {
                BlockHeight = 1, BlockHash = hash
            };
            await _serverService.SendAnnouncement(announcement, BuildServerCallContext(metadata));

            peer.TryAddKnownBlock(hash).ShouldBeFalse();
        }
예제 #12
0
        public void AddKnowBlock(BlockAnnouncement blockAnnouncement)
        {
            if (blockAnnouncement.HasFork)
            {
                _recentBlockHeightAndHashMappings.Clear();
                return;
            }

            CurrentBlockHeight = blockAnnouncement.BlockHeight;
            CurrentBlockHash   = blockAnnouncement.BlockHash;
            _recentBlockHeightAndHashMappings[CurrentBlockHeight] = CurrentBlockHash;
            while (_recentBlockHeightAndHashMappings.Count > 10)
            {
                _recentBlockHeightAndHashMappings.TryRemove(_recentBlockHeightAndHashMappings.Keys.Min(), out _);
            }
        }
예제 #13
0
        public async Task ValidateAnnouncement_Success()
        {
            var chain = await _blockchainService.GetChainAsync();

            var blockAnnouncement = new BlockAnnouncement
            {
                BlockHash   = HashHelper.ComputeFrom("SyncBlockHash"),
                BlockHeight = chain.LastIrreversibleBlockHeight + 1
            };

            var validateResult =
                await _blockSyncValidationService.ValidateAnnouncementBeforeSyncAsync(chain, blockAnnouncement,
                                                                                      GetEncodedPubKeyString());

            validateResult.ShouldBeTrue();
        }
        private async Task ProcessNewBlockAsync(BlockAnnouncement blockAnnouncement, string senderPubkey)
        {
            var chain = await _blockchainService.GetChainAsync();

            if (!await _blockSyncValidationService.ValidateAnnouncementBeforeSyncAsync(chain, blockAnnouncement, senderPubkey))
            {
                return;
            }

            await _blockSyncService.SyncByAnnouncementAsync(chain, new SyncAnnouncementDto
            {
                SyncBlockHash          = blockAnnouncement.BlockHash,
                SyncBlockHeight        = blockAnnouncement.BlockHeight,
                SuggestedPeerPubkey    = senderPubkey,
                BatchRequestBlockCount = _blockSyncOptions.MaxBatchRequestBlockCount
            });
        }
예제 #15
0
        public Task BroadcastAnnounceAsync(BlockHeader blockHeader)
        {
            var blockHash = blockHeader.GetHash();

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

            var blockAnnouncement = new BlockAnnouncement
            {
                BlockHash   = blockHash,
                BlockHeight = blockHeader.Height
            };

            foreach (var peer in _peerPool.GetPeers())
            {
                try
                {
                    if (peer.KnowsBlock(blockHash))
                    {
                        continue; // block already known to this peer
                    }
                    peer.EnqueueAnnouncement(blockAnnouncement, async ex =>
                    {
                        peer.TryAddKnownBlock(blockHash);
                        if (ex != null)
                        {
                            Logger.LogInformation(ex, $"Could not broadcast announcement to {peer} " +
                                                  $"- status {peer.ConnectionStatus}.");

                            await HandleNetworkException(peer, ex);
                        }
                    });
                }
                catch (NetworkException ex)
                {
                    Logger.LogWarning(ex, $"Could not enqueue announcement to {peer} " +
                                      $"- status {peer.ConnectionStatus}.");
                }
            }

            return(Task.CompletedTask);
        }
예제 #16
0
        public Task ProcessAnnouncement(BlockAnnouncement announcement, ServerCallContext context)
        {
            if (announcement?.BlockHash == null)
            {
                Logger.LogError($"Received null announcement or header from {context.GetPeerInfo()}.");

                return(Task.CompletedTask);
            }

            Logger.LogDebug($"Received announce {announcement.BlockHash} from {context.GetPeerInfo()}.");

            var peer = _connectionService.GetPeerByPubkey(context.GetPublicKey());

            peer?.AddKnowBlock(announcement);

            _ = EventBus.PublishAsync(new AnnouncementReceivedEventData(announcement, context.GetPublicKey()));

            return(Task.CompletedTask);
        }
예제 #17
0
        public Task BroadcastAnnounceAsync(BlockHeader blockHeader, bool hasFork)
        {
            var blockHash = blockHeader.GetHash();

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

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

            foreach (var peer in _peerPool.GetPeers())
            {
                try
                {
                    if (peer.KnowsBlock(blockHash))
                    {
                        return(Task.CompletedTask); // block already known to this peer
                    }
                    peer.EnqueueAnnouncement(blockAnnouncement, async ex =>
                    {
                        peer.TryAddKnownBlock(blockHash);
                        if (ex != null)
                        {
                            Logger.LogError(ex, $"Error while broadcasting announcement to {peer}.");
                            await HandleNetworkException(peer, ex);
                        }
                    });
                }
                catch (NetworkException ex)
                {
                    Logger.LogError(ex, $"Error while broadcasting announcement to {peer}.");
                }
            }

            return(Task.CompletedTask);
        }
        private async Task ProcessNewBlockAsync(BlockAnnouncement blockAnnouncement, string senderPubkey)
        {
            Logger.LogDebug(
                $"Start block sync job, target height: {blockAnnouncement.BlockHeight}, target block hash: {blockAnnouncement.BlockHash}, peer: {senderPubkey}");

            var chain = await _blockchainService.GetChainAsync();

            if (!await _blockSyncValidationService.ValidateAnnouncementBeforeSyncAsync(chain, blockAnnouncement, senderPubkey))
            {
                return;
            }

            await _blockSyncService.SyncByAnnouncementAsync(chain, new SyncAnnouncementDto
            {
                SyncBlockHash          = blockAnnouncement.BlockHash,
                SyncBlockHeight        = blockAnnouncement.BlockHeight,
                SuggestedPeerPubkey    = senderPubkey,
                BatchRequestBlockCount = _blockSyncOptions.MaxBatchRequestBlockCount
            });
        }
예제 #19
0
        public async Task AnnounceAsync_Success()
        {
            AnnouncementReceivedEventData received = null;

            _eventBus.Subscribe <AnnouncementReceivedEventData>(a =>
            {
                received = a;
                return(Task.CompletedTask);
            });

            var header = new BlockAnnouncement
            {
                BlockHeight = 100,
                BlockHash   = Hash.FromRawBytes(new byte[] { 9, 2 })
            };

            await _grpcPeer.SendAnnouncementAsync(header);

            received.ShouldNotBeNull();
            received.Announce.BlockHeight.ShouldBe(100);
        }
예제 #20
0
        /// <summary>
        /// Send a announcement to the peer using the stream call.
        /// Note: this method is not thread safe.
        /// </summary>
        private async Task SendAnnouncementAsync(BlockAnnouncement header)
        {
            if (_announcementStreamCall == null)
            {
                _announcementStreamCall = _client.AnnouncementBroadcastStream(new Metadata {
                    { GrpcConstants.SessionIdMetadataKey, OutboundSessionId }
                });
            }

            try
            {
                await _announcementStreamCall.RequestStream.WriteAsync(header);
            }
            catch (RpcException)
            {
                _announcementStreamCall.Dispose();
                _announcementStreamCall = null;

                throw;
            }
        }
예제 #21
0
        public async Task ValidateAnnouncement_AlreadySynchronized()
        {
            var chain = await _blockchainService.GetChainAsync();

            var blockAnnouncement = new BlockAnnouncement
            {
                BlockHash   = Hash.FromString("SyncBlockHash"),
                BlockHeight = chain.LastIrreversibleBlockHeight + 1
            };

            var validateResult =
                await _blockSyncValidationService.ValidateAnnouncementBeforeSyncAsync(chain, blockAnnouncement,
                                                                                      GetEncodedPubKeyString());

            validateResult.ShouldBeTrue();

            validateResult =
                await _blockSyncValidationService.ValidateAnnouncementBeforeSyncAsync(chain, blockAnnouncement,
                                                                                      GetEncodedPubKeyString());

            validateResult.ShouldBeFalse();
        }
예제 #22
0
        /// <summary>
        /// Send a announcement to the peer using the stream call.
        /// Note: this method is not thread safe.
        /// </summary>
        public async Task SendAnnouncementAsync(BlockAnnouncement header)
        {
            if (!IsConnected)
            {
                return;
            }

            if (_announcementStreamCall == null)
            {
                _announcementStreamCall = _client.AnnouncementBroadcastStream();
            }

            try
            {
                await _announcementStreamCall.RequestStream.WriteAsync(header);
            }
            catch (RpcException e)
            {
                _announcementStreamCall.Dispose();
                _announcementStreamCall = null;

                HandleFailure(e, $"Error during announcement broadcast: {header.BlockHash}.");
            }
        }
예제 #23
0
        private Task ProcessAnnouncementAsync(BlockAnnouncement announcement, string peerPubkey)
        {
            if (announcement?.BlockHash == null)
            {
                Logger.LogWarning($"Received null announcement or header from {peerPubkey}.");
                return(Task.CompletedTask);
            }

            var peer = TryGetPeerByPubkey(peerPubkey);

            if (!peer.TryAddKnownBlock(announcement.BlockHash))
            {
                return(Task.CompletedTask);
            }

            if (peer.SyncState != SyncState.Finished)
            {
                peer.SyncState = SyncState.Finished;
            }

            _ = EventBus.PublishAsync(new AnnouncementReceivedEventData(announcement, peerPubkey));

            return(Task.CompletedTask);
        }
예제 #24
0
        /// <summary>
        /// This method is called when a peer wants to broadcast an announcement.
        /// </summary>
        public override async Task <VoidReply> SendAnnouncement(BlockAnnouncement an, ServerCallContext context)
        {
            await ProcessAnnouncement(an, context);

            return(new VoidReply());
        }
 public AnnouncementReceivedEventData(BlockAnnouncement an, string senderPubKey)
 {
     SenderPubKey = senderPubKey;
     Announce     = an;
 }