public void Stake(Address from, BigInteger stakeAmount)
        {
            Runtime.Expect(stakeAmount >= MinimumValidStake, "invalid amount");
            Runtime.Expect(Runtime.IsWitness(from), "witness failed");

            var balance = Runtime.GetBalance(DomainSettings.StakingTokenSymbol, from);

            if (stakeAmount > balance)
            {
                var diff = stakeAmount - balance;
                throw new BalanceException("SOUL", from, diff);
                balance = stakeAmount; // debug mode only, otherwise a exception will prevent it from reaching here
            }

            Runtime.Expect(balance >= stakeAmount, $"balance: {balance} stake: {stakeAmount} not enough balance to stake at " + from);

            Runtime.TransferTokens(DomainSettings.StakingTokenSymbol, from, this.Address, stakeAmount);

            EnergyStake stake;

            if (_stakeMap.ContainsKey <Address>(from))
            {
                stake = _stakeMap.Get <Address, EnergyStake>(from);
            }
            else
            {
                stake = new EnergyStake()
                {
                    stakeTime   = new Timestamp(0),
                    stakeAmount = 0,
                };
            }

            stake.stakeTime    = Runtime.Time;
            stake.stakeAmount += stakeAmount;
            _stakeMap.Set <Address, EnergyStake>(from, stake);

            Runtime.AddMember(DomainSettings.StakersOrganizationName, this.Address, from);

            var claimList  = _claimMap.Get <Address, StorageList>(from);
            var claimEntry = new EnergyClaim()
            {
                stakeAmount = stakeAmount,
                claimDate   = this.Runtime.Time,
                isNew       = true,
            };

            claimList.Add(claimEntry);

            var logEntry = new VotingLogEntry()
            {
                timestamp = this.Runtime.Time,
                amount    = stakeAmount
            };
            var votingLogbook = _voteHistory.Get <Address, StorageList>(from);

            votingLogbook.Add(logEntry);

            // masters membership
            var masterAccountThreshold = GetMasterThreshold();

            if (stake.stakeAmount >= masterAccountThreshold && !IsMaster(from))
            {
                var nextClaim = GetMasterClaimDate(2);

                Runtime.AddMember(DomainSettings.MastersOrganizationName, this.Address, from);
                _masterClaims.Set <Address, Timestamp>(from, nextClaim);

                _masterAgeMap.Set <Address, Timestamp>(from, Runtime.Time);
            }
        }
Beispiel #2
0
        // NOTE - witness not required, as anyone should be able to call this, permission is granted based on consensus
        public void SetValidator(Address target, BigInteger index, ValidatorType type)
        {
            Runtime.Expect(target.IsUser, "must be user address");
            Runtime.Expect(type == ValidatorType.Primary || type == ValidatorType.Secondary, "invalid validator type");

            var primaryValidators   = GetValidatorCount(ValidatorType.Primary);
            var secondaryValidators = GetValidatorCount(ValidatorType.Secondary);

            Runtime.Expect(index >= 0, "invalid index");

            var totalValidators = GetMaxTotalValidators();

            Runtime.Expect(index < totalValidators, "invalid index");

            var expectedType = index < GetMaxPrimaryValidators() ? ValidatorType.Primary : ValidatorType.Secondary;

            Runtime.Expect(type == expectedType, "unexpected validator type");

            var requiredStake = Runtime.CallContext(NativeContractKind.Stake, nameof(StakeContract.GetMasterThreshold), target).AsNumber();
            var stakedAmount  = Runtime.GetStake(target);

            Runtime.Expect(stakedAmount >= requiredStake, "not enough stake");

            if (index > 0)
            {
                var isPreviousSet = _validators.ContainsKey <BigInteger>(index - 1);
                Runtime.Expect(isPreviousSet, "previous validator slot is not set");

                var previousEntry = _validators.Get <BigInteger, ValidatorEntry>(index - 1);
                Runtime.Expect(previousEntry.type != ValidatorType.Invalid, " previous validator has unexpected status");
            }

            if (primaryValidators > 0)
            {
                var isValidatorProposed = _validators.ContainsKey <BigInteger>(index);

                if (isValidatorProposed)
                {
                    var currentEntry = _validators.Get <BigInteger, ValidatorEntry>(index);
                    if (currentEntry.type != ValidatorType.Proposed)
                    {
                        Runtime.Expect(currentEntry.type == ValidatorType.Invalid, "invalid validator state");
                        isValidatorProposed = false;
                    }
                }

                if (isValidatorProposed)
                {
                    Runtime.Expect(Runtime.IsWitness(target), "invalid witness");
                }
                else
                {
                    if (primaryValidators > 1)
                    {
                        var pollName     = ConsensusContract.SystemPoll + ValidatorPollTag;
                        var obtainedRank = Runtime.CallContext("consensus", "GetRank", pollName, target).AsNumber();
                        Runtime.Expect(obtainedRank >= 0, "no consensus for electing this address");
                        Runtime.Expect(obtainedRank == index, "this address was elected at a different index");
                    }
                    else
                    {
                        var firstValidator = GetValidatorByIndex(0).address;
                        Runtime.Expect(Runtime.IsWitness(firstValidator), "invalid witness");
                    }

                    type = ValidatorType.Proposed;
                }
            }
            else
            {
                Runtime.Expect(Runtime.IsWitness(Runtime.GenesisAddress), "invalid witness");
            }

            var entry = new ValidatorEntry()
            {
                address  = target,
                election = Runtime.Time,
                type     = type,
            };

            _validators.Set <BigInteger, ValidatorEntry>(index, entry);

            if (type == ValidatorType.Primary)
            {
                var newValidators = GetValidatorCount(ValidatorType.Primary);
                Runtime.Expect(newValidators > primaryValidators, "number of primary validators did not change");
            }
            else
            if (type == ValidatorType.Secondary)
            {
                var newValidators = GetValidatorCount(ValidatorType.Secondary);
                Runtime.Expect(newValidators > secondaryValidators, "number of secondary validators did not change");
            }

            if (type != ValidatorType.Proposed)
            {
                Runtime.AddMember(DomainSettings.ValidatorsOrganizationName, this.Address, target);
            }

            Runtime.Notify(type == ValidatorType.Proposed ? EventKind.ValidatorPropose : EventKind.ValidatorElect, Runtime.Chain.Address, target);
        }