Пример #1
0
        public async Task Announce_ShouldPublishEvent_Test()
        {
            AnnouncementReceivedEventData received = null;

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

            await _service.SendAnnouncement(null, BuildServerCallContext());

            Assert.Null(received);

            var pubkey   = _peerPool.GetPeers(true).First().Info.Pubkey;
            var metadata = new Metadata {
                {
                    GrpcConstants.PubkeyMetadataKey, pubkey
                }
            };

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

            Assert.NotNull(received);
            Assert.Equal(10, received.Announce.BlockHeight);
            Assert.Equal(received.Announce.BlockHash, hash);
        }
Пример #2
0
        public async Task Disconnect_ShouldRemovePeer()
        {
            await _service.Disconnect(new DisconnectReason(), BuildServerCallContext(new Metadata {
                { GrpcConstants.PubkeyMetadataKey, NetworkTestConstants.FakePubkey2 }
            }));

            Assert.Empty(_peerPool.GetPeers(true));
        }
Пример #3
0
        public async Task Disconnect_ShouldRemovePeer()
        {
            await _service.Disconnect(new DisconnectReason(), BuildServerCallContext(new Metadata {
                { GrpcConsts.PubkeyMetadataKey, "0454dcd0afc20d015e328666d8d25f3f28b13ccd9744eb6b153e4a69709aab399" }
            }));

            Assert.Empty(_peerPool.GetPeers(true));
        }
Пример #4
0
        public async Task DisconnectAsync_Success()
        {
            var peers = _pool.GetPeers();

            peers.Count.ShouldBe(2);

            await _grpcPeer.SendDisconnectAsync();

            peers = _pool.GetPeers();
            peers.Count.ShouldBe(1);
        }
Пример #5
0
        public async Task DisconnectAsync_Success_Test()
        {
            var peers = _pool.GetPeers(true);

            peers.Count.ShouldBe(2);

            await _grpcPeer.DisconnectAsync(true);

            peers = _pool.GetPeers(true);
            peers.Count.ShouldBe(1);
        }
Пример #6
0
        public async Task ConfirmHandshake_Test()
        {
            PeerConnectedEventData received = null;

            _eventBus.Subscribe <PeerConnectedEventData>(t =>
            {
                received = t;
                return(Task.CompletedTask);
            });
            var request = new ConfirmHandshakeRequest();
            var context = BuildServerCallContext(null, "ipv4:127.0.0.1:7878");

            var result = await _serverService.ConfirmHandshake(request, context);

            result.ShouldBe(new VoidReply());
            received.ShouldBe(null);

            var peer     = _peerPool.GetPeers(true).First();
            var pubkey   = peer.Info.Pubkey;
            var metadata = new Metadata {
                { GrpcConstants.PubkeyMetadataKey, pubkey }
            };

            context = BuildServerCallContext(metadata, "ipv4:127.0.0.1:7878");
            result  = await _serverService.ConfirmHandshake(request, context);

            result.ShouldBe(new VoidReply());
            received.ShouldNotBeNull();
        }
Пример #7
0
        public async Task DoHandshake_MaxPeersPerHostReached_Test()
        {
            var peerEndpoint = new IPEndPoint(IPAddress.Parse("1.2.3.4"), 1234);

            var firstPeerFromHostResp = await _connectionService.DoHandshakeAsync(peerEndpoint, GetHandshake("pubKey1"));

            firstPeerFromHostResp.Error.ShouldBe(HandshakeError.HandshakeOk);

            var secondPeerFromHostResp = await _connectionService.DoHandshakeAsync(peerEndpoint, GetHandshake("pubKey2"));

            secondPeerFromHostResp.Error.ShouldBe(HandshakeError.ConnectionRefused);

            _peerPool.GetPeers(true).Count.ShouldBe(1);
            _peerPool.GetHandshakingPeers().Values.Count.ShouldBe(0);
        }
Пример #8
0
        public async Task StopAsync(bool gracefulDisconnect = true)
        {
            try
            {
                await _server.KillAsync();
            }
            catch (InvalidOperationException)
            {
                // if server already shutdown, we continue and clear the channels.
            }

            foreach (var peer in _peerPool.GetPeers(true))
            {
                if (gracefulDisconnect)
                {
                    try
                    {
                        await peer.SendDisconnectAsync();
                    }
                    catch (RpcException e)
                    {
                        Logger.LogError(e, $"Error sending disconnect {peer}.");
                    }
                }

                await peer.StopAsync();
            }
        }
Пример #9
0
        public async Task DisconnectPeersAsync(bool gracefulDisconnect)
        {
            var peers = _peerPool.GetPeers(true);

            foreach (var peer in peers)
            {
                await peer.DisconnectAsync(gracefulDisconnect);
            }
        }
Пример #10
0
        public async Task <NodeList> DiscoverNodesAsync()
        {
            Random rnd = new Random();

            var peers = _peerPool.GetPeers()
                        .OrderBy(x => rnd.Next())
                        .Take(NetworkConstants.DefaultDiscoveryPeersToRequestCount)
                        .ToList();

            var discoveredNodes = new NodeList();

            foreach (var peer in peers)
            {
                try
                {
                    var nodes = await peer.GetNodesAsync();

                    if (nodes != null && nodes.Nodes.Count > 0)
                    {
                        Logger.LogDebug($"Discovery: {peer} responded with the following nodes: {nodes}.");

                        var added = await _nodeManager.AddOrUpdateNodesAsync(nodes);

                        if (added != null)
                        {
                            discoveredNodes.Nodes.AddRange(added.Nodes);
                        }
                    }
                    else
                    {
                        Logger.LogDebug($"Discovery: {peer} responded with no nodes.");
                    }
                }
                catch (NetworkException ex)
                {
                    Logger.LogError(ex, $"Error during discover - {peer}.");
                }
            }

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

            // Check that a peer did not send us this node
            var localPubKey = await _accountService.GetPublicKeyAsync();

            string hexPubkey = localPubKey.ToHex();

            discoveredNodes.Nodes.RemoveAll(n => n.Pubkey.ToHex().Equals(hexPubkey));

            return(discoveredNodes);
        }
Пример #11
0
        /// <summary>
        /// Updates the current target for the initial sync. For now this method will
        /// not have any effect if the sync is already finished or the target has not
        /// been initialized.
        /// </summary>
        /// <returns></returns>
        public async Task UpdateSyncStateAsync()
        {
            // This method should only be called when the sync target has already been found and the
            // node is syncing.

            if (SyncState != SyncState.Syncing)
            {
                Logger.LogWarning("Trying to update the sync, but it is either finished or not yet been initialized.");
                return;
            }

            var chain = await _blockchainService.GetChainAsync();

            // if the current LIB is higher than the recorded target, update
            // the peers current LIB height. Note that this condition will
            // also be true when the node starts.
            if (chain.LastIrreversibleBlockHeight >= _syncStateProvider.SyncTarget)
            {
                var handshake = await _handshakeProvider.GetHandshakeAsync();

                // Update handshake information of all our peers
                var tasks = _peerPool.GetPeers().Select(async peer =>
                {
                    try
                    {
                        await peer.DoHandshakeAsync(handshake);
                    }
                    catch (NetworkException e)
                    {
                        Logger.LogError(e, "Error while handshaking.");
                    }

                    Logger.LogDebug($"Peer {peer} last known LIB is {peer.LastKnownLibHeight}.");
                }).ToList();

                await Task.WhenAll(tasks);
                await UpdateSyncTargetAsync();
            }
        }
        public async Task <IBlockIndex> FindLastLastIrreversibleBlockAsync(string senderPubKey)
        {
            var senderPeer = _peerPool.FindPeerByPublicKey(senderPubKey);

            if (senderPeer == null)
            {
                return(null);
            }

            var orderedBlocks = senderPeer.RecentBlockHeightAndHashMappings.OrderByDescending(p => p.Key).ToList();

            var chain = await _blockchainService.GetChainAsync();

            var chainContext = new ChainContext {
                BlockHash = chain.BestChainHash, BlockHeight = chain.BestChainHeight
            };
            var pubkeyList = (await _dpoSInformationProvider.GetCurrentMinerList(chainContext)).ToList();

            var peers = _peerPool.GetPeers().Where(p => pubkeyList.Contains(p.Info.Pubkey)).ToList();

            var pubKey = (await _accountService.GetPublicKeyAsync()).ToHex();

            if (peers.Count == 0 && !pubkeyList.Contains(pubKey))
            {
                return(null);
            }

            foreach (var block in orderedBlocks)
            {
                var peersHadBlockAmount = peers.Where(p =>
                {
                    p.RecentBlockHeightAndHashMappings.TryGetValue(block.Key, out var hash);
                    return(hash == block.Value);
                }).Count();
                if (pubkeyList.Contains(pubKey) &&
                    _knownBlockCacheProvider.TryGetBlockByHeight(block.Key, out var blockHash) &&
                    blockHash == block.Value)
                {
                    peersHadBlockAmount++;
                }

                var sureAmount = pubkeyList.Count.Mul(2).Div(3) + 1;
                if (peersHadBlockAmount >= sureAmount)
                {
                    Logger.LogDebug($"LIB found in network layer: height {block.Key}");
                    return(new BlockIndex(block.Value, block.Key));
                }
            }

            return(null);
        }
Пример #13
0
        public void QueryPeers_Test()
        {
            var    commonHost     = "12.34.56.67";
            string commonPort     = "1900";
            string commonEndpoint = commonHost + ":" + commonPort;

            var peer1 = CreatePeer(commonEndpoint);

            _peerPool.TryAddPeer(peer1);
            var peer2 = CreatePeer(commonEndpoint);

            _peerPool.TryAddPeer(peer2);
            var peer3 = CreatePeer("12.34.56.64:1900");

            _peerPool.TryAddPeer(peer3);
            var peer4 = CreatePeer("12.34.56.61:1900", isReady: false);

            _peerPool.TryAddPeer(peer4);

            var peers = _peerPool.GetPeers();

            peers.Count.ShouldBe(3);

            peers = _peerPool.GetPeers(true);
            peers.Count.ShouldBe(4);

            peers = _peerPool.GetPeersByHost(commonHost);
            peers.Count.ShouldBe(2);
            peers.ShouldContain(peer1);
            peers.ShouldContain(peer2);

            var peer = _peerPool.FindPeerByEndpoint(peer3.RemoteEndpoint);

            peer.ShouldBe(peer3);

            peer = _peerPool.FindPeerByPublicKey(peer3.Info.Pubkey);
            peer.ShouldBe(peer3);
        }
        public async Task DiscoverNodesAsync()
        {
            var peers = _peerPool.GetPeers()
                        .OrderBy(x => RandomHelper.GetRandom())
                        .Take(NetworkConstants.DefaultDiscoveryPeersToRequestCount)
                        .ToList();

            foreach (var peer in peers)
            {
                var result = await _peerDiscoveryJobProcessor.SendDiscoveryJobAsync(peer);

                if (!result)
                {
                    Logger.LogWarning($"Send discovery job failed: {peer}");
                }
            }
        }
Пример #15
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();
        }
Пример #16
0
        /// <summary>
        /// Based on the given list of peer, will update the sync target. It take the peers that have an LIB higher
        /// than (our LIB + offset), these constitute the possible nodes to sync to. If this group constitutes at
        /// least ceil(2/3 * peer_count), take the one with the smallest LIB as target. Like this:
        /// peer count: 1, nodes that must be higher: 1 - Note: if only one peer, sync.
        /// peer count: 2, nodes that must be higher: 2
        /// peer count: 3, nodes that must be higher: 2
        /// peer count: 4, nodes that must be higher: 3
        /// </summary>
        /// <returns></returns>
        private async Task UpdateSyncTargetAsync()
        {
            // set the target to the lowest LIB
            var chain = await _blockchainService.GetChainAsync();

            var peers = _peerPool.GetPeers().ToList();

            long minSyncTarget = chain.LastIrreversibleBlockHeight + NetworkOptions.InitialSyncOffset;

            // determine the peers that are high enough to sync to
            var candidates = peers
                             .Where(p => p.LastKnownLibHeight >= minSyncTarget)
                             .OrderBy(p => p.LastKnownLibHeight)
                             .ToList();

            if (candidates.Count == 0)
            {
                // no peer has a LIB to sync to, stop the sync.
                await SetSyncAsFinishedAsync();

                Logger.LogInformation($"Finishing sync, not enough peers have a sufficiently high LIB (peer count: {_peerPool.PeerCount}).");
            }
            else
            {
                // If there's more than 2/3 of the nodes that we can
                // sync to, take the lowest of them as target.
                var minLib = candidates.First().LastKnownLibHeight;

                if (candidates.Count >= Math.Ceiling(2d / 3 * peers.Count))
                {
                    SetSyncTarget(minLib);
                    Logger.LogDebug($"Set sync target to {minLib}.");
                }
                else
                {
                    await SetSyncAsFinishedAsync();

                    Logger.LogInformation("Finishing sync, no peer has as a LIB high enough.");
                }
            }
        }
        private async Task <Block> GenerateNewBlockAndAnnouncementToPeers(int number = 1)
        {
            var chain = await _blockchainService.GetChainAsync();

            var hash = await _blockchainService.GetBlockHashByHeightAsync(chain, 6, chain.LongestChainHash);

            var block = await _blockchainService.GetBlockByHashAsync(hash);

            var peers = _peerPool.GetPeers();

            for (var i = 0; i < number; i++)
            {
                var grpcPeer = peers[i] as GrpcPeer;
                grpcPeer.AddKnowBlock(new BlockAnnouncement
                {
                    BlockHash   = block.GetHash(),
                    BlockHeight = block.Height
                });
            }

            return(block);
        }
        public async Task ProcessPeerInvalidTransactionAsync(Hash transactionId)
        {
            var knowsTransactionPeers = _peerPool.GetPeers().Where(p => p.KnowsTransaction(transactionId)).ToList();
            var toRemovePeerPubkey    = new List <string>();

            foreach (var knowsTransactionPeer in knowsTransactionPeers)
            {
                var host = knowsTransactionPeer.RemoteEndpoint.Host;
                if (_peerInvalidTransactionProvider.TryMarkInvalidTransaction(host, transactionId))
                {
                    continue;
                }

                var peers = _peerPool.GetPeersByHost(host);
                toRemovePeerPubkey.AddRange(peers.Select(p => p.Info.Pubkey));

                _peerInvalidTransactionProvider.TryRemoveInvalidRecord(host);
            }

            foreach (var pubkey in toRemovePeerPubkey)
            {
                await _networkService.RemovePeerByPubkeyAsync(pubkey);
            }
        }
Пример #19
0
        public async Task BroadcastAnnounceAsync_OnePeerThrows_ShouldNotBlockOthers()
        {
            int successfulBcasts = await _networkService.BroadcastAnnounceAsync(new BlockHeader());

            Assert.Equal(successfulBcasts, _peerPool.GetPeers().Count - 1);
        }
Пример #20
0
 public List <PeerInfo> GetPeers()
 {
     return(_peerPool.GetPeers(true).Select(PeerInfoHelper.FromNetworkPeer).ToList());
 }
Пример #21
0
 public List <string> GetPeerIpList()
 {
     return(_peerPool.GetPeers(true).Select(p => p.PeerIpAddress).ToList());
 }
Пример #22
0
 public List <PeerInfo> GetPeers(bool includeFailing = true)
 {
     return(_peerPool.GetPeers(includeFailing).Select(PeerInfoHelper.FromNetworkPeer).ToList());
 }
Пример #23
0
 public void GetPeers_ShouldIncludeFailing()
 {
     Assert.Equal(_networkService.GetPeers().Count, _peerPool.GetPeers(true).Count);
 }