Example #1
0
        private JObject GetCurrentPhase()
        {
            var attendanceDetectionPhase = _systemContractReader.IsAttendanceDetectionPhase();
            var vrfSubmissionPhase       = _systemContractReader.IsVrfSubmissionPhase();
            var keyGenPhase = _systemContractReader.IsKeyGenPhase();

            return(new JObject
            {
                ["AttendanceSubmissionPhase"] = attendanceDetectionPhase,
                ["VrfSubmissionPhase"] = vrfSubmissionPhase,
                ["KeyGenPhase"] = keyGenPhase,
            });
        }
Example #2
0
        private JObject GetCurrentCycle()
        {
            var attendanceDetectionPhase = _systemContractReader.IsAttendanceDetectionPhase();
            var vrfSubmissionPhase       = _systemContractReader.IsVrfSubmissionPhase();
            var keyGenPhase = _systemContractReader.IsKeyGenPhase();
            var phase       = attendanceDetectionPhase ? "AttendanceSubmissionPhase" :
                              vrfSubmissionPhase ? "VrfSubmissionPhase" :
                              keyGenPhase ? "KeyGenPhase" : "None";

            return(new JObject
            {
                ["currentPeriod"] = phase,
                ["cycle"] = _blockManager.GetHeight() / StakingContract.CycleDuration,
            });
        }
        private void Run()
        {
            try
            {
                const ulong checkInterval          = 1000;
                var         lastCheckedBlockHeight = (ulong)0;
                var         passingCycle           = -1;
                Logger.LogInformation($"Validator status manager started, {_withdrawTriggered}, {_stakeSize}, {_stopRequested}");

                while (!_withdrawTriggered)
                {
                    if (_stopRequested)
                    {
                        break;
                    }
                    if (lastCheckedBlockHeight == _stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight() ||
                        GetCurrentCycle() == passingCycle)
                    {
                        Thread.Sleep(TimeSpan.FromMilliseconds(checkInterval));
                        continue;
                    }

                    lastCheckedBlockHeight = _stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight();
                    Logger.LogInformation($"Check {lastCheckedBlockHeight} height");

                    if (_sendingTxHash != null)
                    {
                        if (_stateManager.LastApprovedSnapshot.Transactions.GetTransactionByHash(_sendingTxHash) ==
                            null)
                        {
                            Logger.LogInformation(
                                $"Transaction {_sendingTxHash.ToHex()} submitted, waiting for including in block");
                            Thread.Sleep(TimeSpan.FromMilliseconds(checkInterval));
                            continue;
                        }

                        _sendingTxHash = null;
                    }

                    var stake = _systemContractReader.GetStake().ToBigInteger();
                    Logger.LogInformation($"Stake size is {stake}");
                    var isStaker = !stake.IsZero;

                    if (!isStaker)
                    {
                        var coverFeesAmount = new BigInteger(10) * BigInteger.Pow(10, 18);
                        Logger.LogInformation($"Trying to become staker");
                        var balance =
                            _stateManager.CurrentSnapshot.Balances.GetBalance(_systemContractReader.NodeAddress());
                        Logger.LogInformation($"Balance is {balance.ToWei()}");
                        if (_stakeSize is null)
                        {
                            Logger.LogInformation("Stake size is null, cannot become staker");
                            continue;
                        }
                        Logger.LogInformation($"Stake size is {_stakeSize}");
                        var isEnoughBalance = balance.ToWei() > _stakeSize.Value + coverFeesAmount;
                        if (isEnoughBalance)
                        {
                            var rolls = _stakeSize.Value / StakingContract.TokenUnitsInRoll;
                            Logger.LogInformation($"Sending transaction to become staker for {rolls} rolls");
                            BecomeStaker(rolls * StakingContract.TokenUnitsInRoll);
                            _stakeSize = null;
                            continue;
                        }

                        Logger.LogInformation($"Not enough balance to become staker");
                        continue;
                    }

                    var requestCycle = _systemContractReader.GetWithdrawRequestCycle();
                    Logger.LogInformation($"Request cycle is {requestCycle}");
                    if (requestCycle != 0)
                    {
                        Logger.LogInformation(
                            $"Stake withdrawal triggered externally in cycle {requestCycle}. Processing withdrawal...");
                        _withdrawTriggered = true;
                        continue;
                    }

                    if (_systemContractReader.IsAttendanceDetectionPhase() &&
                        _systemContractReader.IsPreviousValidator() && !_systemContractReader.IsCheckedIn())
                    {
                        Logger.LogInformation(
                            $"The node is previous validator. Trying to submit attendance detection.");
                        SubmitAttendanceDetection();
                        continue;
                    }

                    if (_systemContractReader.IsNextValidator())
                    {
                        Logger.LogDebug($"The node chosen as next validator. Nothing to do.");
                        passingCycle = GetCurrentCycle();
                        continue;
                    }

                    if (!_systemContractReader.IsAbleToBeValidator() || !_systemContractReader.IsVrfSubmissionPhase())
                    {
                        Logger.LogInformation($"Current submission phase missed. Waiting for the next one.");
                        passingCycle = GetCurrentCycle();
                        continue;
                    }

                    var(isWinner, proof) = GetVrfProof(stake);
                    if (isWinner)
                    {
                        Logger.LogDebug(
                            $"The node won the VRF lottery. Submitting transaction to become the next cycle validator");
                        SubmitVrf(proof);
                        continue;
                    }

                    Logger.LogInformation($"The node didn't win the VRF lottery. Waiting for the next cycle.");
                    passingCycle = GetCurrentCycle();
                }

                lastCheckedBlockHeight = 0;
                passingCycle           = -1;

                // Try to withdraw stake
                while (!_systemContractReader.GetStake().IsZero())
                {
                    if (_stopRequested)
                    {
                        break;
                    }
                    if (_sendingTxHash != null)
                    {
                        if (_stateManager.LastApprovedSnapshot.Transactions.GetTransactionByHash(_sendingTxHash) ==
                            null)
                        {
                            Logger.LogInformation(
                                $"Transaction {_sendingTxHash.ToHex()} submitted, waiting for including in block");
                            Thread.Sleep(TimeSpan.FromMilliseconds(checkInterval));
                            continue;
                        }

                        _sendingTxHash = null;
                    }

                    if (lastCheckedBlockHeight == _stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight() ||
                        GetCurrentCycle() == passingCycle)
                    {
                        Thread.Sleep(TimeSpan.FromMilliseconds(checkInterval));
                        continue;
                    }

                    Logger.LogWarning($"Trying to withdraw stake");

                    lastCheckedBlockHeight = _stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight();

                    if (_systemContractReader.IsAttendanceDetectionPhase() &&
                        _systemContractReader.IsPreviousValidator() && !_systemContractReader.IsCheckedIn())
                    {
                        Logger.LogInformation(
                            $"The node is previous validator. Trying to submit attendance detection.");
                        SubmitAttendanceDetection();
                        continue;
                    }

                    var requestCycle = _systemContractReader.GetWithdrawRequestCycle();
                    if (requestCycle == 0)
                    {
                        if (IsNextValidator())
                        {
                            Logger.LogWarning($"Stake reserved for the next cycle. Waiting for the next cycle.");
                            passingCycle = GetCurrentCycle();
                            continue;
                        }

                        RequestStakeWithdrawal();
                        passingCycle = GetCurrentCycle();
                        Logger.LogWarning($"Submitted withdrawal stake request. Waiting for the next cycle.");
                        continue;
                    }

                    if (GetCurrentCycle() <= requestCycle)
                    {
                        Logger.LogInformation(
                            $"Stake withdrawal request in cycle {requestCycle}, current cycle is {GetCurrentCycle()}. " +
                            $"Waiting for the next cycle to withdraw stake..."
                            );
                        passingCycle = GetCurrentCycle();
                        continue;
                    }

                    if (!IsWithdrawalPhase())
                    {
                        Logger.LogWarning($"Waiting for withdrawal phase...");
                        continue;
                    }

                    WithdrawStakeTx();
                    Logger.LogWarning(
                        $"Stake withdrawal transaction submitted. Waiting for the next block to ensure withdrawal succeeded.");
                }

                _started = false;
                Logger.LogWarning($"Stake withdrawn. Validator status manager stopped.");
            }
            catch (Exception e)
            {
                Logger.LogCritical($"Fatal error in validator status manager, exiting: {e}");
                Environment.Exit(1);
            }
        }