public ValidatorEntry[] GetValidators() { var totalValidators = (int)Runtime.GetGovernanceValue(ValidatorCountTag); var result = new ValidatorEntry[totalValidators]; for (int i = 0; i < totalValidators; i++) { result[i] = GetValidatorByIndex(i); } return(result); }
// 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); }