void AddValidNode(NodeInfo nodeInfo) { if (!nodeInfo.IsPublicEndPoint) { return; } if (nodeInfo.NodeId == LocalId) { return; } if (!_bucket.Contains(nodeInfo.NodeId)) { Log.Trace($"Adding new node {nodeInfo.PublicEndPoint}.", this); } var evictNode = _bucket.AddOrUpdate(nodeInfo); if (evictNode != null) { lock (_lock) { if (_evictionsCount > 8) { return; } _evictionsCount++; } TaskRunner.Run(async() => { var client = new NodeClient(evictNode.PublicEndPoint); var ni = await client.DownloadNodeInfo(); if (ni.ResultType == DownloadResultTypes.Ok) { _bucket.AddOrUpdate(evictNode); } else { _bucket.Remove(evictNode.NodeId); _bucket.AddOrUpdate(nodeInfo); } lock (_lock) { _evictionsCount--; } }); } }
async Task DownloadBlock(long blockId, ChainSyncItem chainSyncItem, HashSet <NodeConnection> nodeConnections, int tries = 0) { var retry = false; var sync = chainSyncItem.Sync; try { await sync.DownloadLock.WaitAsync(); SyncDownload download; lock (sync.Lock) { sync.NewBlocks.TryGetValue(blockId, out download); if (download == null) { return; } if (!download.TimedOut && download.Downloading) { return; } download.Downloading = true; download.DownloadTime = DateTime.UtcNow; } nodeConnections = nodeConnections ?? new HashSet <NodeConnection>(); foreach (var connection in nodeConnections) { var nodeInfo = connection.NodeInfo; if (nodeInfo.IsPublicEndPoint && nodeInfo.NodeId != _configuration.LocaleNodeInfo.NodeId) { var client = new NodeClient(nodeInfo.PublicEndPoint); var blockData = (await client.DownloadBlockData(chainSyncItem.ChainType, chainSyncItem.ChainId, chainSyncItem.ChainIndex, blockId)).Data; if (blockData != null) { download.UpdateBlockData(blockData); await HandleBlockData(blockData, nodeConnections); goto end; } else { retry = true; } } } foreach (var endPoint in chainSyncItem.Chain.AvailableEndpoints) { var client = new NodeClient(endPoint.EndPoint); if (endPoint.NodeInfo == null) { endPoint.NodeInfo = (await client.DownloadNodeInfo(_configuration.NetworkPublicKey)).Data; } if (endPoint.NodeInfo != null && endPoint.NodeInfo.NodeId != _configuration.LocaleNodeInfo.NodeId) { var blockData = (await client.DownloadBlockData(chainSyncItem.ChainType, chainSyncItem.ChainId, chainSyncItem.ChainIndex, blockId)).Data; if (blockData != null) { download.UpdateBlockData(blockData); await HandleBlockData(blockData, nodeConnections); goto end; } else { retry = true; } } } foreach (var connection in nodeConnections) { await connection.Send(new NodeBlockDataRequestMessage(chainSyncItem.ChainType, blockId, chainSyncItem.ChainId, chainSyncItem.ChainIndex) { SignKey = _configuration.LocaleNodePrivateKey }); await Task.Delay(50); } end: lock (sync.Lock) { download.Downloading = false; } } catch (Exception ex) { Log.HandleException(ex); } finally { sync.DownloadLock.Release(); } if (retry && tries < 10) { await Task.Delay(50 *(tries + 1)); TaskRunner.Run(() => DownloadBlock(blockId, chainSyncItem, nodeConnections, tries + 1)); } }
async Task Loop() { while (!_node.HasQuit) { try { var count = 0; for (var i = 0; i < 5; i++) { var nodeInfo = _kademlia.GetRandomNode(); if (nodeInfo != null) { if (!IsConnected(nodeInfo.NodeId)) { await Connect(nodeInfo); } count++; } } if (count == 0 && ConnectionCount <= 2) { foreach (var beacon in _node.NodeConfiguration.BeaconNodes) { var client = new NodeClient(beacon); var nodeInfo = (await client.DownloadNodeInfo(_kademlia.NetworkKey)).Data; if (nodeInfo != null && !IsConnected(nodeInfo.NodeId)) { await Connect(nodeInfo, beacon); } } } foreach (var item in _autoConnect) { if (item.NodeInfo == null) { var client = new NodeClient(item.EndPoint); item.NodeInfo = (await client.DownloadNodeInfo(_kademlia.NetworkKey)).Data; if (item.NodeInfo != null) { lock (_lock) { _trustedNodeIds.Add(item.NodeInfo.NodeId); } } } if (item.NodeInfo != null) { if (!IsConnected(item.NodeInfo, true)) { await Connect(item.NodeInfo, item.EndPoint); } } } var close = new List <NodeConnection>(); lock (_lock) { foreach (var incoming in _incomingConnections) { foreach (var outgoing in _outgoingConnections) { if (incoming.NodeInfo.NodeId == outgoing.NodeInfo.NodeId) { close.Add(incoming); } } } } foreach (var conn in close) { await conn.Close(DisconnectReasons.AlreadyConnected); } await Task.Delay(Time.Seconds(5), _node.QuitToken); if (_node.HasQuit) { return; } } catch (Exception ex) { Log.IgnoreException(ex, this); } } }
async Task <Dictionary <Tuple <int, uint, ChainType>, ChainSyncItem> > GetChainSyncItems() { var chains = new List <Chain.Chain> { _chainManager.CoreChain }; chains.AddRange(_chainManager.ServiceChains.Values); chains.AddRange(_chainManager.DataChains.Values); chains.AddRange(_chainManager.MaintainChains.Values); var chainSyncs = new Dictionary <Tuple <int, uint, ChainType>, ChainSyncItem>(); var remotes = new List <RemoteSyncItem>(); foreach (var chain in chains) { var chainType = chain.ChainType; var chainId = chain.ChainId; var chainIndex = chain.ChainIndex; var chainSync = new ChainSyncItem(chain); chainSyncs.Add(new Tuple <int, uint, ChainType>(chainId, chainIndex, chainType), chainSync); Chain.Chain.CreateRequiredDirectories(_storage, chain.ChainType, chainId, chainIndex, true); var endPoints = chain.AvailableEndpoints; foreach (var endPoint in endPoints) { var client = new NodeClient(endPoint.EndPoint); var nodeInfo = endPoint.NodeInfo; if (nodeInfo == null) { nodeInfo = (await client.DownloadNodeInfo(_configuration.NetworkPublicKey)).Data; } if (nodeInfo != null && !(nodeInfo.NodeId == _configuration.LocaleNodeInfo.NodeId)) { if (endPoint.NodeInfo == null) { endPoint.NodeInfo = nodeInfo; } var lastBlockInfo = (await client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data; if (lastBlockInfo != null) { var blockSliceInfo = (await client.DownloadBlockStorageSliceInfo(chainType, chainId, chainIndex)).Data; var transactionSliceInfo = (await client.DownloadTransactionStorageSliceInfo(chainType, chainId, chainIndex)).Data; var remote = new RemoteSyncItem(client, lastBlockInfo); chainSync.AddRemote(remote); if (blockSliceInfo != null) { chainSync.UpdateLowestFoundBlockSliceId(blockSliceInfo.FirstStoredSliceId); } if (transactionSliceInfo != null) { chainSync.UpdateLowestFoundTransactionSliceId(transactionSliceInfo.FirstStoredSliceId); } remotes.Add(remote); } } } } // get latest chain info foreach (var chain in chainSyncs.Values) { var chainType = chain.ChainType; var chainId = chain.ChainId; var chainIndex = chain.ChainIndex; foreach (var remote in chain.Remotes) { var lastBlockInfo = (await remote.Client.DownloadLastBlockInfo(chainType, chainId, chainIndex)).Data; chain.UpdateLastBlockInfo(lastBlockInfo); } } return(chainSyncs); }
async Task <bool> QueryEndPoint(Uri endpoint, bool querySubNodes) { try { if (endpoint == LocalNodeInfo.PublicEndPoint) { return(false); } var client = new NodeClient(endpoint); var nodeInfoResult = (await client.DownloadNodeInfo()); if (nodeInfoResult.ResultType == DownloadResultTypes.Timeout || nodeInfoResult.ResultType == DownloadResultTypes.NotFound) { return(false); } var nodeInfo = nodeInfoResult.Data; if (nodeInfo != null) { if (nodeInfo.NetworkKey != NetworkKey) { Log.Info($"Queryied node not is invalid {nodeInfo.PublicEndPoint}. Wrong network key.", this); return(false); } { if (nodeInfo.NodeId == LocalId) { return(false); } var queryResult = (await client.DownloadKademliaNodes(nodeInfo.NodeKey, LocalId)).Data; if (queryResult != null) { if (nodeInfo.IsPublicEndPoint) { AddValidNode(nodeInfo); } else { Log.Warn($"Node has no public endpoint {endpoint}.", this); } if (querySubNodes) { foreach (var node in queryResult.Nodes) { if (node.IsPublicEndPoint) { var c2 = new NodeClient(node.PublicEndPoint); var ni2 = (await c2.DownloadNodeInfo()).Data; if (ni2 != null && ni2.NetworkKey == NetworkKey && node.NodeKey == ni2.NodeKey) { AddValidNode(ni2); } } } } } } } } catch (Exception ex) { Log.IgnoreException(ex, this); Log.Error($"Node is invalid {endpoint}.", this); } return(true); }
public async Task <bool> Start(string[] args, CancellationTokenSource quiteToken) { _quitToken = quiteToken; if (_quitToken.IsCancellationRequested) { return(false); } var dataPath = "heleusdata"; var genesis = false; var sync = false; var run = false; var init = false; var newChainConfig = false; if (args.Length == 1) { dataPath = args[0]; run = true; } else if (args.Length == 2) { dataPath = args[0]; var cmd = args[1]; if (cmd == "init") { init = true; } else if (cmd == "run") { run = true; } else if (cmd == "sync") { sync = true; } else if (cmd == "chainconfig") { newChainConfig = true; } else if (cmd == "genesis") { genesis = true; } else { Usage(); return(false); } } else { Usage(); return(false); } if ((run || sync) && !File.Exists(Path.Combine(dataPath, $"{nameof(NodeConfig).ToLower()}.txt"))) { Usage(); var dp = new DirectoryInfo(dataPath); Log.Error($"Data path {dp.FullName} not initalized.", this); return(false); } Storage = new Storage(dataPath); if (!Storage.IsWriteable) { Log.Fatal($"Data path {Storage.Root} is not writeable!", this); return(false); } if (genesis) { Storage.DeleteDirectory("cache"); Storage.DeleteDirectory("chains"); } PubSub = Log.PubSub = new PubSub(); Log.Write($"Starting Heleus Node (Version {Program.Version})."); Log.Trace($"PID {System.Diagnostics.Process.GetCurrentProcess().Id}"); Log.Write($"Data path is '{Storage.Root.FullName}'."); var config = Config.Load <NodeConfig>(Storage); Log.AddIgnoreList(config.LogIgnore); Log.LogLevel = config.LogLevel; if (Program.IsDebugging) { Log.LogLevel = LogLevels.Trace; } if (newChainConfig) { var chainConfig = Config.Load <ChainConfig>(Storage, true); //if (chainConfig.Chains.Count == 0) { Log.Write("Chain config generated."); chainConfig.Chains.Add(new ChainConfig.ChainInfo { ChainKeys = new List <ChainConfig.ChainKeyInfo> { new ChainConfig.ChainKeyInfo { ChainKey = string.Empty, ChainKeyPassword = string.Empty, AttachementKey = -1 } } }); Config.Save(chainConfig); } return(false); } if (init) { Log.Write("Config file generated."); return(false); } if (!genesis) { if (config.NetworkPublicKey.IsNullOrEmpty()) { Log.Write("Network key not set. Querying beacon nodes."); var beacons = config.BeaconNodes; foreach (var beacon in beacons) { Log.Write($"Querying beacon node {beacon}."); var client = new NodeClient(new Uri(beacon)); var nodeInfo = (await client.DownloadNodeInfo()).Data; if (nodeInfo != null) { config.NetworkPublicKey = nodeInfo.NetworkKey.HexString; Config.Save(config); Log.Write($"Network key set to {config.NetworkPublicKey}."); break; } } } if (config.NetworkPublicKey.IsNullOrEmpty()) { Log.Write("No valid network key found or set.", this); return(false); } } NodeConfiguration = new NodeConfiguration(config, Config.Load <CoreKeyConfig>(Storage, false), Config.Load <ChainConfig>(Storage, false)); Host = new Host(config); AttachementManager = new AttachementManager(this); ChainManager = new ChainManager(this); if (!await ChainManager.Initalize()) { return(false); } if (genesis) { var result = GenesisBlock.Generate(Storage); var blockData = new BlockData <CoreBlock>(result.Block, result.Signature); await ChainManager.Start(false); await ChainManager.CoreChain.BlockStorage.StoreBlock(blockData); ChainManager.ConsumeBlockData(blockData); Log.Write($"Genesis block and keys generated. Network public key: {result.NetworkPublicKey.HexString}."); var coreKeyConfig = Config.Load <CoreKeyConfig>(Storage); coreKeyConfig.Key = result.NetworkVoteKey.HexString; coreKeyConfig.Password = result.NetworkVotePassword; config.NetworkPublicKey = result.NetworkPublicKey.HexString; Config.Save(config); Config.Save(coreKeyConfig); await ChainManager.Stop(); await ChainManager.Start(true); if (result.ServiceTransactions.Count > 0) { foreach (var serviceTransactions in result.ServiceTransactions) { var chainId = serviceTransactions.Key; var transactions = serviceTransactions.Value; var serviceChain = ChainManager.GetServiceChain(chainId); var maintainChain = ChainManager.GetMaintainChain(chainId); if (serviceChain != null) { var generator = new ServiceBlockGenerator(ChainManager.CoreChain, serviceChain, maintainChain, null); foreach (var transaction in transactions) { generator.ConsumeTransaction(transaction); } var serviceBlock = generator.GenerateBlock(0, 0); var serviceBlockData = new BlockData <ServiceBlock>(serviceBlock, new BlockSignatures(serviceBlock)); await serviceChain.BlockStorage.StoreBlock(serviceBlockData); serviceChain.ConsumeBlockData(serviceBlockData); } } } await ChainManager.Stop(); return(false); } SyncManager = new SyncManager(this); await SyncManager.Start(); //if (!await SyncManager.Start()) // return false; if (sync) { Log.Write("Sync done."); return(false); } AttachementManager.Start(); Kademlia = new Kademlia(Storage, this); TransactionManager = new TransactionManager(this); CouncilManager = new CouncilManager(this); NodeServer = new NodeServer(this, config.MaxIncomingConnections, config.MaxOutgoingConnectoins); ClientServer = new ClientServer(this); if (Host.EnableRemoteServices) { ServiceServer = new ServiceServer(); } await(Host as Host).Start(this); return(true); }