Beispiel #1
0
        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));
            }
        }
Beispiel #3
0
        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);
                }
            }
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }