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); }
public async Task Disconnect_ShouldRemovePeer() { await _service.Disconnect(new DisconnectReason(), BuildServerCallContext(new Metadata { { GrpcConstants.PubkeyMetadataKey, NetworkTestConstants.FakePubkey2 } })); Assert.Empty(_peerPool.GetPeers(true)); }
public async Task Disconnect_ShouldRemovePeer() { await _service.Disconnect(new DisconnectReason(), BuildServerCallContext(new Metadata { { GrpcConsts.PubkeyMetadataKey, "0454dcd0afc20d015e328666d8d25f3f28b13ccd9744eb6b153e4a69709aab399" } })); Assert.Empty(_peerPool.GetPeers(true)); }
public async Task DisconnectAsync_Success() { var peers = _pool.GetPeers(); peers.Count.ShouldBe(2); await _grpcPeer.SendDisconnectAsync(); peers = _pool.GetPeers(); peers.Count.ShouldBe(1); }
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); }
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(); }
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); }
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(); } }
public async Task DisconnectPeersAsync(bool gracefulDisconnect) { var peers = _peerPool.GetPeers(true); foreach (var peer in peers) { await peer.DisconnectAsync(gracefulDisconnect); } }
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); }
/// <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); }
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}"); } } }
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(); }
/// <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); } }
public async Task BroadcastAnnounceAsync_OnePeerThrows_ShouldNotBlockOthers() { int successfulBcasts = await _networkService.BroadcastAnnounceAsync(new BlockHeader()); Assert.Equal(successfulBcasts, _peerPool.GetPeers().Count - 1); }
public List <PeerInfo> GetPeers() { return(_peerPool.GetPeers(true).Select(PeerInfoHelper.FromNetworkPeer).ToList()); }
public List <string> GetPeerIpList() { return(_peerPool.GetPeers(true).Select(p => p.PeerIpAddress).ToList()); }
public List <PeerInfo> GetPeers(bool includeFailing = true) { return(_peerPool.GetPeers(includeFailing).Select(PeerInfoHelper.FromNetworkPeer).ToList()); }
public void GetPeers_ShouldIncludeFailing() { Assert.Equal(_networkService.GetPeers().Count, _peerPool.GetPeers(true).Count); }