Esempio n. 1
0
        private async Task SendNodesInfoToGroupAsync(ChatId chatid)
        {
            var wc = new WebClient();
            var json = wc.DownloadString(LyraGlobal.SelectNode(_network) + "LyraNode/GetBillboard");
            var bb = JsonConvert.DeserializeObject<BillBoardData>(json);
            var sb = new StringBuilder();

            sb.AppendLine($"*Consensus Algorithm (PBFT) Settings*");
            sb.AppendLine($"Total Needed Minimal Node Number: {ProtocolSettings.Default.ConsensusTotalNumber}");
            sb.AppendLine($"Consensus Win Number: {ProtocolSettings.Default.ConsensusWinNumber}");
            sb.AppendLine($"Maxmimum Failed Node Number: {ProtocolSettings.Default.ConsensusNumber}");
            sb.AppendLine($"Current Running Node Count: {bb.AllNodes.Count}");
            sb.AppendLine($"Current Nodes can do Authorizing: {bb.AllNodes.Count(a => a.Value.ableToAuthorize)}");
            var cando = bb.canDoConsensus ? "Yes" : "No";
            sb.AppendLine($"Consensus Can be Made Now: {cando}");

            sb.AppendLine("\n*Fully Functional Nodes List*\n");

            sb.AppendLine("`" + bb.AllNodes.Values.Where(a => a.ableToAuthorize)
                .Select(b => b.accountID.Shorten()).Aggregate((c, d) => c + "\n" + d) + "`");

            sb.AppendLine("\n*Nodes which has trouble*\n");

            sb.AppendLine("`" + bb.AllNodes.Values.Where(a => !a.ableToAuthorize)
                .Aggregate(new StringBuilder(), 
                    (c, n) => c.AppendLine(n.accountID.Shorten() + ": " + n.FailReasons.Select(a => "[" + a + "]").Aggregate((a, b) => a + b)), 
                    sb => sb.ToString()) + "`");

            await SendGroupMessageAsync(chatid, sb.ToString());
        }
Esempio n. 2
0
        public override async Task <APIResultCodes> PreSendAuthAsync(DagSystem sys, SendTransferBlock block, TransactionBlock last)
        {
            var dexid = block.Tags.ContainsKey("dexid") ? block.Tags["dexid"] : null;

            if (dexid == null)
            {
                return(APIResultCodes.InvalidAccountId);
            }

            decimal mintamount    = 0;
            var     mintamountstr = block.Tags.ContainsKey("amount") ? block.Tags["amount"] : null;

            if (mintamountstr == null || !decimal.TryParse(mintamountstr, out mintamount) || mintamount <= 0)
            {
                return(APIResultCodes.InvalidAmount);
            }

            // verify if sender is dex server
            if (block.AccountID != LyraGlobal.GetDexServerAccountID(LyraNodeConfig.GetNetworkId()))
            {
                return(APIResultCodes.InvalidDexServer);
            }

            // verify dex wallet owner
            var brkr = await sys.Storage.FindLatestBlockAsync(dexid) as IBrokerAccount;

            if (brkr == null)
            {
                return(APIResultCodes.InvalidBrokerAcount);
            }

            return(APIResultCodes.Success);
        }
Esempio n. 3
0
        private async Task SendHeight(ChatId chatid)
        {
            var wc = new WebClient();
            var json = wc.DownloadString(LyraGlobal.SelectNode(_network) + "LyraNode/GetSyncState");
            var bb = JsonConvert.DeserializeObject<GetSyncStateAPIResult>(json);

            await SendGroupMessageAsync(chatid, $"Current Height: *{bb.NewestBlockUIndex}*");
        }
Esempio n. 4
0
        private async Task SendNodesInfoToGroupAsync()
        {
            var wc   = new WebClient();
            var json = wc.DownloadString(LyraGlobal.SelectNode("devnet") + "LyraNode/GetBillboard");
            var bb   = JsonConvert.DeserializeObject <BillBoard>(json);
            var sb   = new StringBuilder();

            foreach (var node in bb.AllNodes.Values)
            {
                sb.AppendLine($"{node.AccountID}");
                sb.AppendLine($"Staking Balance: {node.Balance}");
                sb.AppendLine($"Last Staking Time: {node.LastStaking}");
                sb.AppendLine();
            }
            await SendGroupMessageAsync(sb.ToString());
        }
Esempio n. 5
0
        protected override async Task <APIResultCodes> AuthorizeImplAsync <T>(DagSystem sys, T tblock)
        {
            if (!(tblock is TokenMintBlock))
            {
                return(APIResultCodes.InvalidBlockType);
            }

            var block = tblock as TokenMintBlock;

            if (string.IsNullOrWhiteSpace(block.MintBy))
            {
                return(APIResultCodes.InvalidTokenMint);
            }
            if (string.IsNullOrWhiteSpace(block.GenesisHash))
            {
                return(APIResultCodes.InvalidTokenMint);
            }
            if (block.MintAmount <= 0)
            {
                return(APIResultCodes.InvalidTokenMint);
            }

            if (block.MintBy != LyraGlobal.GetDexServerAccountID(LyraNodeConfig.GetNetworkId()))
            {
                return(APIResultCodes.InvalidDexServer);
            }

            // IDexWallet interface
            var brkauth = new DexWalletAuthorizer();
            var brkret  = await brkauth.AuthorizeAsync(sys, tblock);

            if (brkret == APIResultCodes.Success)
            {
                return(await Lyra.Shared.StopWatcher.TrackAsync(() => base.AuthorizeImplAsync(sys, tblock), "DexTokenMintAuthorizer->TransactionAuthorizer"));
            }
            else
            {
                return(brkret);
            }
        }
        /// <summary>
        /// two ways to begin view changing: either one third of all voters requested, or local requested.
        ///
        /// </summary>
        /// <returns></returns>
        internal async Task BeginChangeViewAsync(ViewChangeReason reason)
        {
            _log.LogInformation($"BeginChangeViewAsync: VID: {ViewId} Req: {reqMsgs.Count} Reply: {replyMsgs.Count} Commit: {commitMsgs.Count} Votes {commitMsgs.Count}/{LyraGlobal.GetMajority(_context.Board.AllVoters.Count)}/{_context.Board.AllVoters.Count} Replyed: {replySent} Commited: {commitSent}");

            _reason = reason;
            var lastSb = await _sys.Storage.GetLastServiceBlockAsync();

            if (lastSb == null)
            {
                // genesis?
                _log.LogCritical($"BeginChangeViewAsync has null service block. should not happend. error.");
                return;
            }

            _isViewChanging = true;

            ShiftView(lastSb.Height + 1);
            selectedSuccess = false;

            _log.LogInformation($"View change for ViewId {ViewId} begin at {TimeStarted}");

            CalculateLeaderCandidate();

            var lastCons = await _sys.Storage.GetLastConsolidationBlockAsync();

            var req = new ViewChangeRequestMessage
            {
                From             = _sys.PosWallet.AccountId,
                ViewID           = ViewId,
                prevViewID       = lastSb.Height,
                requestSignature = Signatures.GetSignature(_sys.PosWallet.PrivateKey,
                                                           $"{lastSb.Hash}|{lastCons.Hash}", _sys.PosWallet.AccountId),
            };

            _context.Send2P2pNetwork(req);
            await CheckRequestAsync(req);
        }
        private async Task CheckAllStatsAsync()
        {
            if (!IsViewChanging)
            {
                RemoveOutDatedMsgs();

                if (reqMsgs.Count > _context.Board.AllVoters.Count - LyraGlobal.GetMajority(_context.Board.AllVoters.Count))
                {
                    var sb = new StringBuilder();
                    foreach (var msg in reqMsgs)
                    {
                        sb.Append($"{msg.Key.Shorten()}, ");
                    }

                    _log.LogInformation($"too many view change request, {sb.ToString()}. force into view change mode");

                    // too many view change request. force into view change mode
                    await _context.GotViewChangeRequestAsync(ViewId, reqMsgs.Count);
                }

                return;
            }

            // request
            if (!replySent && reqMsgs.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count))
            {
                _log.LogInformation($"CheckAllStats VID: {ViewId} Time: {TimeStarted} Req: {reqMsgs.Count} Reply: {replyMsgs.Count} Commit: {commitMsgs.Count} Votes {commitMsgs.Count}/{LyraGlobal.GetMajority(_context.Board.AllVoters.Count)}/{_context.Board.AllVoters.Count} Replyed: {replySent} Commited: {commitSent}");

                if (string.IsNullOrEmpty(nextLeader))
                {
                    CalculateLeaderCandidate();
                }

                var reply = new ViewChangeReplyMessage
                {
                    From      = _sys.PosWallet.AccountId,
                    ViewID    = ViewId,
                    Result    = Blocks.APIResultCodes.Success,
                    Candidate = nextLeader
                };

                _context.Send2P2pNetwork(reply);

                replySent = true;
                await CheckReplyAsync(reply);
            }

            if (!commitSent)
            {
                if (replyMsgs.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count))
                {
                    _log.LogInformation($"CheckAllStats VID: {ViewId} Time: {TimeStarted} Req: {reqMsgs.Count} Reply: {replyMsgs.Count} Commit: {commitMsgs.Count} Votes {commitMsgs.Count}/{LyraGlobal.GetMajority(_context.Board.AllVoters.Count)}/{_context.Board.AllVoters.Count} Replyed: {replySent} Commited: {commitSent}");

                    // reply
                    // only if we have enough reply
                    var decQr = from rep in replyMsgs.Values
                                where rep.msg.Result == Blocks.APIResultCodes.Success
                                group rep by rep.msg.Candidate into g
                                select new { Candidate = g.Key, Count = g.Count() };

                    var decisions = decQr.OrderByDescending(x => x.Count).ToList();

                    var candidateQR = decisions.FirstOrDefault();

                    var sb = new StringBuilder();
                    sb.AppendLine($"Decisions for View ID: {ViewId}");
                    foreach (var x in decisions)
                    {
                        sb.AppendLine($"\t{x.Candidate.Shorten()}: {x.Count}");
                    }
                    _log.LogInformation(sb.ToString());

                    if (candidateQR?.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count))
                    {
                        var commit = new ViewChangeCommitMessage
                        {
                            From      = _sys.PosWallet.AccountId,
                            ViewID    = ViewId,
                            Candidate = candidateQR.Candidate,
                            Consensus = ConsensusResult.Yea
                        };

                        _context.Send2P2pNetwork(commit);
                        commitSent = true;
                        await CheckCommitAsync(commit);
                    }
                    else
                    {
                        //_log.LogInformation($"CheckAllStats, By ReplyMsgs, not commit, top candidate {candidateQR?.Candidate.Shorten()} has {candidateQR?.Count} votes");
                    }
                }
            }

            if (!selectedSuccess)
            {
                // commit
                var q = from rep in commitMsgs.Values
                        group rep by rep.msg.Candidate into g
                        select new { Candidate = g.Key, Count = g.Count() };

                var candidate = q.OrderByDescending(x => x.Count).FirstOrDefault();
                if (candidate != null)
                {
                    if (nextLeader != candidate.Candidate)
                    {
                        _log.LogWarning($"Next Leader {nextLeader} not {candidate.Candidate}");
                    }
                    nextLeader = candidate.Candidate;
                    if (candidate?.Count >= LyraGlobal.GetMajority(_context.Board.AllVoters.Count))
                    {
                        _log.LogInformation($"CheckAllStats, By CommitMsgs, leader selected {candidate.Candidate} with {candidate.Count} votes.");

                        selectedSuccess = true;
                        _leaderSelected(this, ViewId, candidate.Candidate, candidate.Count, _context.Board.AllVoters);
                    }
                }
            }
        }
        protected override async Task <APIResultCodes> AuthorizeImplAsync <T>(DagSystem sys, T tblock)
        {
            if (!(tblock is TokenGenesisBlock))
            {
                return(APIResultCodes.InvalidBlockType);
            }

            var block = tblock as TokenGenesisBlock;

            // Local node validations - before it sends it out to the authorization sample:
            // 1. check if the account already exists
            if (!(tblock is LyraTokenGenesisBlock))
            {
                if (!await sys.Storage.AccountExistsAsync(block.AccountID))
                {
                    return(APIResultCodes.AccountDoesNotExist); //
                }
                TransactionBlock lastBlock = await sys.Storage.FindLatestBlockAsync(block.AccountID) as TransactionBlock;

                if (lastBlock == null)
                {
                    return(APIResultCodes.CouldNotFindLatestBlock);
                }

                // check LYR balance
                if (lastBlock.Balances[LyraGlobal.OFFICIALTICKERCODE] != block.Balances[LyraGlobal.OFFICIALTICKERCODE] + block.Fee.ToBalanceLong())
                {
                    return(APIResultCodes.InvalidNewAccountBalance);
                }

                // check ticker name
                // https://www.quora.com/What-characters-are-not-allowed-in-a-domain-name
                var r = new Regex(@"[^\w-]|^-|-$");
                if (!block.Ticker.Contains(block.DomainName + "/") || r.IsMatch(block.DomainName))
                {
                    return(APIResultCodes.InvalidDomainName);
                }

                if (r.IsMatch(block.Ticker.Replace(block.DomainName + "/", "")))
                {
                    return(APIResultCodes.InvalidTickerName);
                }

                if (block.RenewalDate > DateTime.UtcNow.Add(TimeSpan.FromDays(3660)) || block.RenewalDate < DateTime.UtcNow)
                {
                    return(APIResultCodes.InvalidTokenRenewalDate);
                }

                if (string.IsNullOrWhiteSpace(block.DomainName))
                {
                    return(APIResultCodes.EmptyDomainName);
                }

                bool tokenIssuerIsSeed0 = block.AccountID == ProtocolSettings.Default.StandbyValidators[0];
                if (!tokenIssuerIsSeed0 && block.AccountID != LyraGlobal.GetDexServerAccountID(LyraNodeConfig.GetNetworkId()))
                {
                    if (block.DomainName.Length < 6)
                    {
                        return(APIResultCodes.DomainNameTooShort);
                    }
                    if (_reservedDomains.Any(a => a.Equals(block.DomainName, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        return(APIResultCodes.DomainNameReserved);
                    }
                }
            }

            if (await sys.Storage.WasAccountImportedAsync(block.AccountID))
            {
                return(APIResultCodes.CannotModifyImportedAccount);
            }

            var tresult = await VerifyTransactionBlockAsync(sys, block);

            if (tresult != APIResultCodes.Success)
            {
                return(tresult);
            }

            // check length
            if (string.IsNullOrWhiteSpace(block.DomainName) || string.IsNullOrWhiteSpace(block.Ticker))
            {
                return(APIResultCodes.InvalidTickerName);
            }

            if (block.DomainName.Length >= 64 || block.Ticker.Length >= 64)
            {
                return(APIResultCodes.InvalidTickerName);
            }

            // check if this token already exists
            //AccountData genesis_blocks = _accountCollection.GetAccount(AccountCollection.GENESIS_BLOCKS);
            //if (genesis_blocks.FindTokenGenesisBlock(testTokenGenesisBlock) != null)
            if (await sys.Storage.FindTokenGenesisBlockAsync(block.Hash, block.Ticker) != null)
            {
                return(APIResultCodes.TokenGenesisBlockAlreadyExists);
            }

            if (block.Fee != (await sys.Storage.GetLastServiceBlockAsync()).TokenGenerationFee)
            {
                return(APIResultCodes.InvalidFeeAmount);
            }

            if (block.NonFungibleType == NonFungibleTokenTypes.Collectible && !block.IsNonFungible)
            {
                return(APIResultCodes.InvalidNFT);
            }

            if (block.IsNonFungible)
            {
                if (!Signatures.ValidateAccountId(block.NonFungibleKey))
                {
                    return(APIResultCodes.InvalidNonFungiblePublicKey);
                }

                // Validate Collectible NFT
                if (block.ContractType == ContractTypes.Collectible)
                {
                    if (block.Precision != 0)
                    {
                        return(APIResultCodes.InvalidNFT);
                    }

                    if (block.NonFungibleType != NonFungibleTokenTypes.Collectible)
                    {
                        return(APIResultCodes.InvalidNFT);
                    }
                }
            }

            return(await Lyra.Shared.StopWatcher.TrackAsync(() => base.AuthorizeImplAsync(sys, tblock), "TokenGenesisAuthorizer->ReceiveTransferAuthorizer"));
        }
Esempio n. 9
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _waitOrder = new AutoResetEvent(false);
            try
            {
                var networkId = LyraNodeConfig.GetNetworkId();

                _log.LogInformation($"{LyraGlobal.PRODUCTNAME} {LyraGlobal.NODE_VERSION} Mode: {Neo.Settings.Default.LyraNode.Lyra.Mode}: Starting node daemon for {networkId}.");

                // something must be initialized first

                Wallet PosWallet;

                string lyrawalletfolder = Wallet.GetFullFolderName(networkId, "wallets");

                if (!Directory.Exists(lyrawalletfolder))
                {
                    Directory.CreateDirectory(lyrawalletfolder);
                }

                var walletStore = new SecuredWalletStore(lyrawalletfolder);
                if (!walletStore.Exists(Neo.Settings.Default.LyraNode.Lyra.Wallet.Name))
                {
                    _log.LogInformation($"Creating wallet for {networkId}.");

                    (var privateKey, var publicKey) = Signatures.GenerateWallet();

                    _log.LogInformation($"The new wallet {Neo.Settings.Default.LyraNode.Lyra.Wallet.Name} for {networkId} was created.");
                    //Console.WriteLine($"Private Key: {privateKey}");
                    _log.LogInformation($"Account ID: {publicKey}");

                    walletStore.Create(Neo.Settings.Default.LyraNode.Lyra.Wallet.Name, Neo.Settings.Default.LyraNode.Lyra.Wallet.Password, networkId, privateKey, publicKey, "");
                    _log.LogInformation($"Wallet saved to: {lyrawalletfolder}{Neo.Settings.Default.LyraNode.Lyra.Wallet.Name}.lyrawallet");
                }

                PosWallet = Wallet.Open(walletStore,
                                        Neo.Settings.Default.LyraNode.Lyra.Wallet.Name,
                                        Neo.Settings.Default.LyraNode.Lyra.Wallet.Password,
                                        LyraRestClient.Create(networkId, "", "NodeService", "1.0", LyraGlobal.SelectNode(networkId) + "Node/"));
                _log.LogInformation($"Staking wallet: {PosWallet.AccountId}");
                PosWallet.SetVoteFor(PosWallet.AccountId);

                var blcokcount = await _store.GetBlockCountAsync();

                if (blcokcount > 0 && networkId == "devnet") // not genesis
                {
                    try
                    {
                        await PosWallet.SyncAsync(null);
                    }
                    catch { }
                }

                var localNode = DagSystem.ActorSystem.ActorOf(Neo.Network.P2P.LocalNode.Props());
                Dag = new DagSystem(_hostEnv, _store, _lyraEventContext, PosWallet, localNode);
                _   = Task.Run(async() => await Dag.StartAsync()).ConfigureAwait(false);
                await Task.Delay(30000);
            }
            catch (Exception ex)
            {
                _log.LogCritical($"NodeService: Error Initialize! {ex}");
            }

            while (!stoppingToken.IsCancellationRequested)
            {
                // do work
                if (_waitOrder.WaitOne(1000))
                {
                    _waitOrder.Reset();
                }
                else
                {
                    // no new order. do house keeping.
                }
            }
        }