982 lines
40 KiB
Go
982 lines
40 KiB
Go
|
|
// verifiedVerdict provides functions to determine the current moderator consensus verdict for a particular identity/message/profile
|
|
// These verdicts are calculated based on the downloaded moderator reviews, and are thus verified
|
|
|
|
package verifiedVerdict
|
|
|
|
// We cannot determine the verified consensus verdict of a message/profile without knowing its metadata.
|
|
// See package contentMetadata for an explanation.
|
|
|
|
// Possible verdicts:
|
|
// -Identity: Banned/Not Banned
|
|
// -Profile/Message: Banned/Approved/Undecided
|
|
|
|
import "seekia/internal/contentMetadata"
|
|
import "seekia/internal/identity"
|
|
import "seekia/internal/encoding"
|
|
import "seekia/internal/moderation/bannedModeratorConsensus"
|
|
import "seekia/internal/moderation/enabledModerators"
|
|
import "seekia/internal/moderation/moderatorScores"
|
|
import "seekia/internal/moderation/reviewStorage"
|
|
import "seekia/internal/network/appNetworkType/getAppNetworkType"
|
|
import "seekia/internal/network/backgroundDownloads"
|
|
import "seekia/internal/profiles/readProfiles"
|
|
|
|
import "errors"
|
|
|
|
//Outputs:
|
|
// -bool: Client is downloading the required reviews/moderator profiles
|
|
// -bool: Parameters Exist
|
|
// -bool: Identity is banned
|
|
// -int: Number of eligible moderators who have banned the identity
|
|
// -float64: Ban Advocates identity score sum (Sum of identity score of all eligible moderators who banned the identity)
|
|
// -[][16]byte: List of all ban advocates (Eligible and banned)
|
|
// -error
|
|
func GetVerifiedIdentityVerdict(identityHash [16]byte, networkType byte)(bool, bool, bool, int, float64, [][16]byte, error){
|
|
|
|
clientIsDownloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(identityHash)
|
|
if (err != nil) { return false, false, false, 0, 0, nil, err }
|
|
if (clientIsDownloadingRequiredReviews == false){
|
|
|
|
return false, false, false, 0, 0, nil, nil
|
|
}
|
|
|
|
appNetworkType, err := getAppNetworkType.GetAppNetworkType()
|
|
if (err != nil) { return false, false, false, 0, 0, nil, err }
|
|
if (appNetworkType != networkType){
|
|
// We are not downloading reviews for this network type.
|
|
return false, false, false, 0, 0, nil, nil
|
|
}
|
|
|
|
//TODO: Add parameters check
|
|
parametersExist := true
|
|
if (parametersExist == false){
|
|
|
|
// We do not have moderation parameters. We cannot determine verdict consensus
|
|
return true, false, false, 0, 0, nil, nil
|
|
}
|
|
|
|
banAdvocatesMap, err := reviewStorage.GetIdentityBanAdvocatesMap(identityHash, networkType)
|
|
if (err != nil) { return false, false, false, 0, 0, nil, err }
|
|
|
|
numberOfEligibleBanAdvocates := 0
|
|
eligibleBanAdvocatesScoreSum := float64(0)
|
|
allEnabledBanAdvocatesList := make([][16]byte, 0)
|
|
|
|
for moderatorIdentityHash, _ := range banAdvocatesMap{
|
|
|
|
moderatorIsEnabled, err := enabledModerators.CheckIfModeratorIsEnabled(true, moderatorIdentityHash, networkType)
|
|
if (err != nil){ return false, false, false, 0, 0, nil, err }
|
|
if (moderatorIsEnabled == false){
|
|
// We will disregard all of this moderators reviews
|
|
continue
|
|
}
|
|
|
|
allEnabledBanAdvocatesList = append(allEnabledBanAdvocatesList, moderatorIdentityHash)
|
|
|
|
downloadingRequiredData, parametersExist, moderatorIsBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(true, moderatorIdentityHash, networkType)
|
|
if (err != nil) { return false, false, false, 0, 0, nil, err }
|
|
if (downloadingRequiredData == false){
|
|
return false, true, false, 0, 0, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, false, 0, 0, nil, nil
|
|
}
|
|
if (moderatorIsBanned == true){
|
|
continue
|
|
}
|
|
|
|
scoreIsKnown, moderatorScore, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, false, 0, 0, nil, err }
|
|
if (scoreIsKnown == false || scoreIsSufficient == false){
|
|
continue
|
|
}
|
|
|
|
numberOfEligibleBanAdvocates += 1
|
|
eligibleBanAdvocatesScoreSum += moderatorScore
|
|
}
|
|
|
|
//Outputs:
|
|
// -bool: Downloading required data
|
|
// -bool: Parameters exist
|
|
// -bool: Identity is banned
|
|
// -error
|
|
getBanConsensusVerdict := func()(bool, bool, bool, error){
|
|
|
|
identityType, err := identity.GetIdentityTypeFromIdentityHash(identityHash)
|
|
if (err != nil){
|
|
identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
|
|
return false, false, false, errors.New("getBanConsensusVerdict reached with invalid identityHash: " + identityHashHex)
|
|
}
|
|
if (identityType != "Moderator"){
|
|
|
|
//TODO: Retrieve this variable from parameters
|
|
minimumBanAdvocatesNeeded := 3
|
|
|
|
if (numberOfEligibleBanAdvocates < minimumBanAdvocatesNeeded){
|
|
return true, true, false, nil
|
|
}
|
|
return true, true, true, nil
|
|
}
|
|
|
|
// identityType == "Moderator"
|
|
|
|
// For moderators, the banning process is more complicated
|
|
// Moderators must have a higher score to ban another moderator
|
|
// We use another package to calculate the result
|
|
|
|
downloadingRequiredData, parametersExist, moderatorIsBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(true, identityHash, networkType)
|
|
if (err != nil) { return false, false, false, err }
|
|
if (downloadingRequiredData == false){
|
|
return false, false, false, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, false, nil
|
|
}
|
|
|
|
return true, true, moderatorIsBanned, nil
|
|
}
|
|
|
|
downloadingRequiredData, parametersExist, banConsensusVerdict, err := getBanConsensusVerdict()
|
|
if (err != nil) { return false, false, false, 0, 0, nil, err }
|
|
if (downloadingRequiredData == false){
|
|
return false, true, false, 0, 0, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, false, false, 0, 0, nil, nil
|
|
}
|
|
|
|
return true, true, banConsensusVerdict, numberOfEligibleBanAdvocates, eligibleBanAdvocatesScoreSum, allEnabledBanAdvocatesList, nil
|
|
}
|
|
|
|
// This function returns if the provided profile is banned.
|
|
// This function does not take into account if the profile author is banned.
|
|
// A profile with an insufficient number of reviews/reviewers can be "Undecided"
|
|
// Host/Moderator "Undecided" profiles are still considered viewable, only Mate profiles must be "Approved" to be viewable
|
|
//Outputs:
|
|
// -bool: Profile is disabled
|
|
// -bool: Profile metadata is known
|
|
// -int: Profile version
|
|
// -byte: Profile network type
|
|
// -[16]byte: Profile Identity Hash
|
|
// -map[int][27]byte: Profile attribute hashes map (Attribute identifier -> Attribute hash)
|
|
// -bool: Client is downloading required reviews and moderator profiles
|
|
// -bool: Parameters exist
|
|
// -string: Moderator consensus verdict ("Approved"/"Banned"/"Undecided")
|
|
// -int: Number of eligible moderators who have approved the profile
|
|
// -int: Number of eligible moderators who have banned the profile (including a single attribute)
|
|
// -float64: Approve Score Sum (sum of identity scores for all eligible moderators who approved the entire profile)
|
|
// -float64: Ban Score Sum (sum of identity scores for all eligible moderators who banned the profile, including a single attribute)
|
|
// -map[int]int: Attribute Identifier -> Number of eligible approve advocates
|
|
// -map[int]int: Attribute identifier -> Number of eligible ban advocates
|
|
// -This does not include users who banned the full profile without describing which attribute was unruleful
|
|
// -map[int]float64: Attribute identifier -> Sum of all eligible approve advocate identity scores
|
|
// -This includes users who banned the full profile.
|
|
// -map[int]float64: Attribute identifier -> Sum of all eligible ban advocate identity scores
|
|
// -This includes moderators who banned the entire profile
|
|
// -[][16]byte: List of all moderators who have approved the profile (Eligible and banned)
|
|
// -This does not include moderators who have only approved some attributes.
|
|
// -This only includes moderators who have approved the full profile.
|
|
// -[][16]byte: List of all moderators who have banned the profile (eligible and banned)
|
|
// -This includes moderators who have banned only 1 attribute.
|
|
// -int: Number of moderators who have banned the full profile (eligible and banned)
|
|
// -This only includes moderators who have banned the full profile (not including ones who only banned attributes)
|
|
// -map[int][][16]byte: Map of attribute identifier -> List of moderators who have approved attribute (eligible and banned)
|
|
// -map[int][][16]byte: Map of Attribute Identifier -> List of moderators who have banned attribute (eligible and banned)
|
|
// -This does not include moderators who have banned the entire profile without describing which attribute was unruleful
|
|
// -error
|
|
func GetVerifiedProfileVerdict(profileHash [28]byte)(bool, bool, int, byte, [16]byte, map[int][27]byte, bool, bool, string, int, int, float64, float64, map[int]int, map[int]int, map[int]float64, map[int]float64, [][16]byte, [][16]byte, int, map[int][][16]byte, map[int][][16]byte, error){
|
|
|
|
_, profileIsDisabled, err := readProfiles.ReadProfileHashMetadata(profileHash)
|
|
if (err != nil){
|
|
profileHashHex := encoding.EncodeBytesToHexString(profileHash[:])
|
|
return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, errors.New("GetVerifiedProfileVerdict called with invalid profileHash: " + profileHashHex)
|
|
}
|
|
|
|
//TODO: Add parameters check
|
|
parametersExist := true
|
|
|
|
metadataExists, profileVersion, profileNetworkType, profileIdentityHash, _, profileIsDisabledB, _, profileAttributeHashesMap, err := contentMetadata.GetProfileMetadata(profileHash)
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
if (metadataExists == false){
|
|
// We do not have profile metadata, we cannot determine moderator consensus
|
|
return profileIsDisabled, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil
|
|
}
|
|
if (profileIsDisabled != profileIsDisabledB){
|
|
return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, errors.New("GetProfileMetadata returning different profileIsDisabled status than ReadProfileHashMetadata.")
|
|
}
|
|
if (profileIsDisabled == true){
|
|
|
|
return true, true, profileVersion, profileNetworkType, profileIdentityHash, nil, true, parametersExist, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil
|
|
}
|
|
|
|
clientIsDownloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineIdentityVerdicts(profileIdentityHash)
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
if (clientIsDownloadingRequiredReviews == false){
|
|
// We cannot determine verdict. Required reviews are not being downloaded.
|
|
|
|
return false, true, profileVersion, profileNetworkType, profileIdentityHash, profileAttributeHashesMap, false, parametersExist, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil
|
|
}
|
|
|
|
if (parametersExist == false){
|
|
// We dont have parameters. We cannot determine status.
|
|
return false, true, profileVersion, profileNetworkType, profileIdentityHash, profileAttributeHashesMap, true, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil
|
|
}
|
|
|
|
// This stores all moderator identity hashes who reviewed the profile/attributes
|
|
// We use a map to avoid duplicates
|
|
// Map Structure: Reviewer identity hash -> Nothing
|
|
allReviewersMap := make(map[[16]byte]struct{})
|
|
|
|
type fullProfileVerdictInfo struct{
|
|
|
|
// Verdict for full profile ("Approve"/"Ban")
|
|
Verdict string
|
|
|
|
// Time of verdict for full profile
|
|
VerdictTime int64
|
|
}
|
|
|
|
// Map Structure: Author Identity hash -> fullProfileVerdictInfo
|
|
fullProfileVerdictsInfoMap := make(map[[16]byte]fullProfileVerdictInfo)
|
|
|
|
type attributeReviewObject struct{
|
|
|
|
AttributeIdentifier int
|
|
|
|
// Verdict for the attribute ("Approve"/"Ban")
|
|
Verdict string
|
|
|
|
// Time at which the verdict was made
|
|
VerdictTime int64
|
|
}
|
|
|
|
// Map Structure: Reviewer identity hash -> List of attribute review objects
|
|
attributeReviewsMap := make(map[[16]byte][]attributeReviewObject)
|
|
|
|
// First we add full profile reviews
|
|
|
|
fullProfileApproveAdvocatesMap, fullProfileBanAdvocatesMap, err := reviewStorage.GetProfileVerdictMaps(profileHash, profileNetworkType, false, nil)
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
addFullProfileVerdictsToMaps := func(reviewersMap map[[16]byte]int64, verdict string)error{
|
|
|
|
for reviewerIdentityHash, verdictTime := range reviewersMap{
|
|
|
|
allReviewersMap[reviewerIdentityHash] = struct{}{}
|
|
|
|
newVerdictInfoObject := fullProfileVerdictInfo{
|
|
Verdict: verdict,
|
|
VerdictTime: verdictTime,
|
|
}
|
|
|
|
_, exists := fullProfileVerdictsInfoMap[reviewerIdentityHash]
|
|
if (exists == true){
|
|
return errors.New("Trying to add reviewer to fullProfileVerdictsInfoMap and reviewer entry already exists.")
|
|
}
|
|
fullProfileVerdictsInfoMap[reviewerIdentityHash] = newVerdictInfoObject
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
err = addFullProfileVerdictsToMaps(fullProfileApproveAdvocatesMap, "Approve")
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
err = addFullProfileVerdictsToMaps(fullProfileBanAdvocatesMap, "Ban")
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
// Now we add profile attribute reviews
|
|
|
|
for attributeIdentifier, attributeHash := range profileAttributeHashesMap{
|
|
|
|
addAttributeVerdictsToMap := func(reviewersMap map[[16]byte]int64, verdict string)error{
|
|
|
|
for reviewerIdentityHash, verdictTime := range reviewersMap{
|
|
|
|
allReviewersMap[reviewerIdentityHash] = struct{}{}
|
|
|
|
newAttributeReviewObject := attributeReviewObject{
|
|
AttributeIdentifier: attributeIdentifier,
|
|
Verdict: verdict,
|
|
VerdictTime: verdictTime,
|
|
}
|
|
|
|
existingReviewObjectsList, exists := attributeReviewsMap[reviewerIdentityHash]
|
|
if (exists == false){
|
|
newAttributeReviewObjectsList := []attributeReviewObject{newAttributeReviewObject}
|
|
attributeReviewsMap[reviewerIdentityHash] = newAttributeReviewObjectsList
|
|
} else {
|
|
newAttributeReviewObjectsList := append(existingReviewObjectsList, newAttributeReviewObject)
|
|
attributeReviewsMap[reviewerIdentityHash] = newAttributeReviewObjectsList
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := reviewStorage.GetProfileAttributeVerdictMaps(attributeHash, profileNetworkType, false, nil)
|
|
if (err != nil){ return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
err = addAttributeVerdictsToMap(approveAdvocatesMap, "Approve")
|
|
if (err != nil){ return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
err = addAttributeVerdictsToMap(banAdvocatesMap, "Ban")
|
|
if (err != nil){ return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
}
|
|
|
|
// This keeps track of the number of eligible moderators who approved the full profile
|
|
numberOfEligibleApproveAdvocates := 0
|
|
// This keeps track of the number of eligible moderators who banned the profile
|
|
numberOfEligibleBanAdvocates := 0
|
|
|
|
// This is the sum of all identity scores of all eligible moderators who approved the full profile
|
|
eligibleApproveAdvocateScoresSum := float64(0)
|
|
// This is the sum of all identity scores of all eligible moderators who banned the profile
|
|
eligibleBanAdvocateScoresSum := float64(0)
|
|
|
|
// We need these maps when determining final verdict
|
|
// Map Structure: Attribute identifier -> Number of eligible approve advocates
|
|
eligibleAttributeApproveAdvocateCountsMap := make(map[int]int)
|
|
// Map Structure: Attribute identifier -> Number of eligible ban advocates (not including full profile bans)
|
|
eligibleAttributeBanAdvocateCountsMap := make(map[int]int)
|
|
|
|
// This is a map that keeps track of each attribute's approve and ban weight
|
|
// This is used to determine if the profile is approved or banned
|
|
// Each approve/ban increases attribute weight by the moderator's identity score
|
|
// Approving the entire profile adds to each attribute approve weight
|
|
// Banning the entire profile adds to each attribute ban weight
|
|
// It ignores the reviews of banned/ineligible moderators
|
|
// Map Structure: Attribute identifier -> Attribute weight
|
|
attributeApproveWeightsMap := make(map[int]float64)
|
|
attributeBanWeightsMap := make(map[int]float64)
|
|
|
|
// This is a list of all moderators who have approved the profile (Eligible and banned)
|
|
// This only includes moderators who have approved the full profile.
|
|
// This does not include moderators who have only approved some attributes.
|
|
allProfileApproveAdvocatesList := make([][16]byte, 0)
|
|
|
|
// This is a list of all moderators who have banned the profile (eligible and banned)
|
|
// This includes moderators who have banned only 1 attribute.
|
|
allProfileBanAdvocatesList := make([][16]byte, 0)
|
|
|
|
// This keeps track of the number of moderators who have banned the full profile (eligible and banned)
|
|
numberOfFullProfileBanAdvocates := 0
|
|
|
|
// -This includes moderators who have approved the full profile.
|
|
// Map Structure: Attribute identifier -> List of moderators who have approved attribute (eligible and banned)
|
|
allAttributeApproveAdvocatesMap := make(map[int][][16]byte)
|
|
// -This does not include moderators who have only banned the entire profile, but not the specified attribute
|
|
// Map Structure: Attribute Identifier -> List of moderators who have banned attribute (eligible and banned)
|
|
allAttributeBanAdvocatesMap := make(map[int][][16]byte)
|
|
|
|
// Now we iterate through each moderator to populate the variables we just created
|
|
|
|
for moderatorIdentityHash, _ := range allReviewersMap{
|
|
|
|
moderatorIsEnabled, err := enabledModerators.CheckIfModeratorIsEnabled(true, moderatorIdentityHash, profileNetworkType)
|
|
if (err != nil){ return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
if (moderatorIsEnabled == false){
|
|
// We will disregard all of this moderators reviews
|
|
continue
|
|
}
|
|
|
|
downloadingRequiredData, parametersExist, moderatorIsBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(true, moderatorIdentityHash, profileNetworkType)
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
if (downloadingRequiredData == false){
|
|
// We cannot determine verdict. Required reviews are not being downloaded.
|
|
return false, true, profileVersion, profileNetworkType, profileIdentityHash, profileAttributeHashesMap, false, true, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
// We dont have parameters. We cannot determine status.
|
|
return false, true, profileVersion, profileNetworkType, profileIdentityHash, profileAttributeHashesMap, true, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, nil
|
|
}
|
|
|
|
//Outputs:
|
|
// -bool: Moderator is eligible
|
|
// -float64: Moderator identity score
|
|
// -error
|
|
checkIfModeratorIsEligible := func()(bool, float64, error){
|
|
|
|
if (moderatorIsBanned == true){
|
|
return false, 0, nil
|
|
}
|
|
|
|
scoreIsKnown, moderatorScore, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(moderatorIdentityHash)
|
|
if (err != nil) { return false, 0, err }
|
|
if (scoreIsKnown == false || scoreIsSufficient == false){
|
|
return false, 0, nil
|
|
}
|
|
|
|
return true, moderatorScore, nil
|
|
}
|
|
|
|
moderatorIsEligible, moderatorScore, err := checkIfModeratorIsEligible()
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
// We use the function below to deal with the possibility of a conflict between the profile/attribute verdicts
|
|
// Outputs:
|
|
// -bool: Full profile verdict exists
|
|
// -string: Full profile verdict ("Approve"/"Ban")
|
|
// -map[int]string: Attribute identifier -> Attribute verdict ("Approve"/"Ban")
|
|
// -error
|
|
getModeratorVerdicts := func()(bool, string, map[int]string, error){
|
|
|
|
fullProfileReviewInfoObject, fullProfileReviewExists := fullProfileVerdictsInfoMap[moderatorIdentityHash]
|
|
|
|
attributeReviewObjectsList, anyAttributeReviewExists := attributeReviewsMap[moderatorIdentityHash]
|
|
|
|
if (fullProfileReviewExists == false && anyAttributeReviewExists == false){
|
|
return false, "", nil, errors.New("allReviewersMap contains reviewer without any reviews.")
|
|
}
|
|
|
|
if (fullProfileReviewExists == true && anyAttributeReviewExists == false){
|
|
|
|
fullProfileReviewVerdict := fullProfileReviewInfoObject.Verdict
|
|
|
|
if (fullProfileReviewVerdict == "Approve"){
|
|
// Full profile is approved. All attributes are approved
|
|
|
|
// Map Structure: Attribute identifier -> Attribute verdict
|
|
attributeVerdictsMap := make(map[int]string)
|
|
|
|
for attributeIdentifier, _ := range profileAttributeHashesMap{
|
|
attributeVerdictsMap[attributeIdentifier] = "Approve"
|
|
}
|
|
|
|
return true, "Approve", attributeVerdictsMap, nil
|
|
}
|
|
|
|
emptyMap := make(map[int]string)
|
|
|
|
return true, "Ban", emptyMap, nil
|
|
}
|
|
|
|
if (fullProfileReviewExists == false && anyAttributeReviewExists == true){
|
|
|
|
// Map Structure: Attribute identifier -> Attribute verdict
|
|
attributeReviewsMap := make(map[int]string)
|
|
|
|
for _, attributeReviewObject := range attributeReviewObjectsList{
|
|
|
|
attributeIdentifier := attributeReviewObject.AttributeIdentifier
|
|
attributeVerdict := attributeReviewObject.Verdict
|
|
|
|
attributeReviewsMap[attributeIdentifier] = attributeVerdict
|
|
}
|
|
|
|
return false, "", attributeReviewsMap, nil
|
|
}
|
|
|
|
// The moderator has reviewed the full profile and at least 1 of the profile's attributes
|
|
// We have to take into account that newer reviews will cancel out older reviews
|
|
//
|
|
// These are the two possible conflicts:
|
|
// 1. if a user bans a profile attribute, and then later approves the entire profile, all of their
|
|
// previous attribute ban reviews for the profile are discarded
|
|
// 2. If a user approves a full profile, and then later bans an attribute, their full profile approval review is discarded
|
|
|
|
fullProfileReviewVerdict := fullProfileReviewInfoObject.Verdict
|
|
fullProfileVerdictTime := fullProfileReviewInfoObject.VerdictTime
|
|
|
|
// Outputs:
|
|
// -bool: Full profile verdict exists
|
|
// -string: Full profile verdict
|
|
// -error
|
|
getFullProfileVerdict := func()(bool, string, error){
|
|
|
|
if (fullProfileReviewVerdict == "Ban"){
|
|
return true, "Ban", nil
|
|
}
|
|
|
|
for _, attributeReviewObject := range attributeReviewObjectsList{
|
|
|
|
attributeVerdict := attributeReviewObject.Verdict
|
|
|
|
if (attributeVerdict == "Ban"){
|
|
|
|
attributeVerdictTime := attributeReviewObject.VerdictTime
|
|
|
|
if (attributeVerdictTime > fullProfileVerdictTime){
|
|
// The moderator banned an attribute after approving the full profile
|
|
// We discard their full profile approval
|
|
return false, "", nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return true, "Approve", nil
|
|
}
|
|
|
|
fullProfileReviewExists, fullProfileVerdict, err := getFullProfileVerdict()
|
|
if (err != nil) { return false, "", nil, err }
|
|
|
|
if (fullProfileReviewExists == true && fullProfileVerdict == "Approve"){
|
|
// Full profile is approved. All attributes are approved
|
|
|
|
// Map Structure: Attribute identifier -> Attribute verdict
|
|
attributeVerdictsMap := make(map[int]string)
|
|
|
|
for attributeIdentifier, _ := range profileAttributeHashesMap{
|
|
attributeVerdictsMap[attributeIdentifier] = "Approve"
|
|
}
|
|
|
|
return true, "Approve", attributeVerdictsMap, nil
|
|
}
|
|
|
|
// Map Structure: Attribute identifier -> Attribute verdict
|
|
attributeVerdictsMap := make(map[int]string)
|
|
|
|
for _, attributeReviewObject := range attributeReviewObjectsList{
|
|
|
|
attributeIdentifier := attributeReviewObject.AttributeIdentifier
|
|
attributeVerdict := attributeReviewObject.Verdict
|
|
|
|
attributeVerdictsMap[attributeIdentifier] = attributeVerdict
|
|
}
|
|
|
|
return fullProfileReviewExists, fullProfileVerdict, attributeVerdictsMap, nil
|
|
}
|
|
|
|
fullProfileReviewExists, fullProfileVerdict, attributeVerdictsMap, err := getModeratorVerdicts()
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
if (fullProfileReviewExists == true && fullProfileVerdict == "Ban"){
|
|
|
|
numberOfFullProfileBanAdvocates += 1
|
|
}
|
|
|
|
//Outputs:
|
|
// -bool: Verdict exists
|
|
// -string: Verdict
|
|
getModeratorProfileVerdict := func()(bool, string){
|
|
|
|
if (fullProfileReviewExists == true){
|
|
|
|
return true, fullProfileVerdict
|
|
}
|
|
|
|
// A moderator who has banned a single attribute is considered to have banned the entire profile
|
|
|
|
for _, attributeVerdict := range attributeVerdictsMap{
|
|
|
|
if (attributeVerdict == "Ban"){
|
|
return true, "Ban"
|
|
}
|
|
}
|
|
|
|
return false, ""
|
|
}
|
|
|
|
profileVerdictExists, profileVerdict := getModeratorProfileVerdict()
|
|
if (profileVerdictExists == true){
|
|
|
|
if (profileVerdict == "Approve"){
|
|
allProfileApproveAdvocatesList = append(allProfileApproveAdvocatesList, moderatorIdentityHash)
|
|
|
|
if (moderatorIsEligible == true){
|
|
numberOfEligibleApproveAdvocates += 1
|
|
eligibleApproveAdvocateScoresSum += moderatorScore
|
|
}
|
|
|
|
} else {
|
|
allProfileBanAdvocatesList = append(allProfileBanAdvocatesList, moderatorIdentityHash)
|
|
|
|
if (moderatorIsEligible == true){
|
|
numberOfEligibleBanAdvocates += 1
|
|
eligibleBanAdvocateScoresSum += moderatorScore
|
|
}
|
|
}
|
|
}
|
|
|
|
for attributeIdentifier, attributeVerdict := range attributeVerdictsMap{
|
|
|
|
addIdentityHashToMapEntryList := func(inputMap map[int][][16]byte){
|
|
|
|
currentList, exists := inputMap[attributeIdentifier]
|
|
if (exists == false){
|
|
inputMap[attributeIdentifier] = [][16]byte{moderatorIdentityHash}
|
|
} else {
|
|
currentList = append(currentList, moderatorIdentityHash)
|
|
inputMap[attributeIdentifier] = currentList
|
|
}
|
|
}
|
|
|
|
if (attributeVerdict == "Approve"){
|
|
|
|
addIdentityHashToMapEntryList(allAttributeApproveAdvocatesMap)
|
|
|
|
if (moderatorIsEligible == true){
|
|
eligibleAttributeApproveAdvocateCountsMap[attributeIdentifier] += 1
|
|
}
|
|
|
|
} else {
|
|
|
|
addIdentityHashToMapEntryList(allAttributeBanAdvocatesMap)
|
|
|
|
if (moderatorIsEligible == true){
|
|
eligibleAttributeBanAdvocateCountsMap[attributeIdentifier] += 1
|
|
}
|
|
}
|
|
}
|
|
|
|
if (moderatorIsEligible == true){
|
|
|
|
// Now we add to attributeApproveWeightsMap and attributeBanWeightsMap
|
|
|
|
if (fullProfileReviewExists == true && fullProfileVerdict == "Ban"){
|
|
|
|
// We add weight for every attribute entry
|
|
|
|
for attributeIdentifier, _ := range profileAttributeHashesMap{
|
|
|
|
attributeBanWeightsMap[attributeIdentifier] += moderatorScore
|
|
}
|
|
} else {
|
|
|
|
// We add to each attribute, only when user approved/banned them
|
|
|
|
for attributeIdentifier, attributeVerdict := range attributeVerdictsMap{
|
|
|
|
if (attributeVerdict == "Approve"){
|
|
attributeApproveWeightsMap[attributeIdentifier] += moderatorScore
|
|
} else {
|
|
attributeBanWeightsMap[attributeIdentifier] += moderatorScore
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
userIdentityType, err := identity.GetIdentityTypeFromIdentityHash(profileIdentityHash)
|
|
if (err != nil){ return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
if (len(allProfileApproveAdvocatesList) == 0 && len(allProfileBanAdvocatesList) == 0 && len(allAttributeApproveAdvocatesMap) == 0 && len(allAttributeBanAdvocatesMap) == 0){
|
|
|
|
// No reviews exist.
|
|
// Profile is undecided.
|
|
emptyMapA := make(map[int]int)
|
|
emptyMapB := make(map[int]int)
|
|
emptyMapC := make(map[int]float64)
|
|
emptyMapD := make(map[int]float64)
|
|
emptyListA := make([][16]byte, 0)
|
|
emptyListB := make([][16]byte, 0)
|
|
emptyMapE := make(map[int][][16]byte)
|
|
emptyMapF := make(map[int][][16]byte)
|
|
|
|
return false, true, profileVersion, profileNetworkType, profileIdentityHash, profileAttributeHashesMap, true, true, "Undecided", 0, 0, 0, 0, emptyMapA, emptyMapB, emptyMapC, emptyMapD, emptyListA, emptyListB, 0, emptyMapE, emptyMapF, nil
|
|
}
|
|
|
|
//TODO: Retrieve from parameters
|
|
minimumAttributeApproveAdvocates_Mate := 0 // Applies to all non-canonical attributes even if they are not banned
|
|
minimumAttributeApproveAdvocates_Host := 0 // Only used if attribute/profile is banned
|
|
minimumAttributeApproveAdvocates_Moderator := 0 // Only used if attribute/profile is banned
|
|
|
|
getMinimumNeededApprovers := func()int{
|
|
if (userIdentityType == "Mate"){
|
|
return minimumAttributeApproveAdvocates_Mate
|
|
}
|
|
if (userIdentityType == "Host"){
|
|
return minimumAttributeApproveAdvocates_Host
|
|
}
|
|
// userIdentityType == "Moderator"
|
|
return minimumAttributeApproveAdvocates_Moderator
|
|
}
|
|
|
|
minimumNeededApprovers := getMinimumNeededApprovers()
|
|
|
|
//TODO: Retrieve from parameters
|
|
minimumApprovedRatio_Mate := float64(1.5)
|
|
minimumApprovedRatio_Host := float64(1.7)
|
|
minimumApprovedRatio_Moderator := float64(1.8)
|
|
|
|
getMinimumApprovedRatio := func()float64{
|
|
if (userIdentityType == "Mate"){
|
|
return minimumApprovedRatio_Mate
|
|
}
|
|
if (userIdentityType == "Host"){
|
|
return minimumApprovedRatio_Host
|
|
}
|
|
// userIdentityType == "Moderator"
|
|
return minimumApprovedRatio_Moderator
|
|
}
|
|
|
|
minimumApprovedRatio := getMinimumApprovedRatio()
|
|
|
|
getVerdictConsensus := func()(string, error){
|
|
|
|
// This will be true if any non-canonical attribute is undecided
|
|
nonCanonicalUndecidedExists := false
|
|
|
|
for attributeIdentifier, attributeHash := range profileAttributeHashesMap{
|
|
|
|
_, attributeIsCanonical, err := readProfiles.ReadAttributeHashMetadata(attributeHash)
|
|
if (err != nil){
|
|
attributeHashHex := encoding.EncodeBytesToHexString(attributeHash[:])
|
|
return "", errors.New("profileAttributeHashesMap contains invalid attribute hash: " + attributeHashHex)
|
|
}
|
|
|
|
getAttributeApproveWeight := func()float64{
|
|
|
|
attributeApproveWeight, approveWeightExists := attributeApproveWeightsMap[attributeIdentifier]
|
|
if (approveWeightExists == false){
|
|
return 0
|
|
}
|
|
return attributeApproveWeight
|
|
}
|
|
|
|
getAttributeBanWeight := func()float64{
|
|
|
|
attributeBanWeight, banWeightExists := attributeBanWeightsMap[attributeIdentifier]
|
|
if (banWeightExists == false){
|
|
return 0
|
|
}
|
|
return attributeBanWeight
|
|
}
|
|
|
|
approveWeight := getAttributeApproveWeight()
|
|
|
|
banWeight := getAttributeBanWeight()
|
|
|
|
if (approveWeight < 0 || banWeight < 0){
|
|
// This should never happen.
|
|
return "", errors.New("Attribute approve/ban weight is negative.")
|
|
}
|
|
|
|
if (approveWeight == 0 && banWeight == 0){
|
|
|
|
if (userIdentityType == "Mate" && attributeIsCanonical == false){
|
|
// Attribute status is Undecided
|
|
nonCanonicalUndecidedExists = true
|
|
}
|
|
continue
|
|
}
|
|
if (approveWeight == 0 && banWeight > 0){
|
|
// The attribute is banned, thus the entire profile is banned.
|
|
return "Banned", nil
|
|
}
|
|
|
|
getNumberOfAttributeApproveAdvocates := func()int{
|
|
|
|
numberOfAttributeApproveAdvocates, exists := eligibleAttributeApproveAdvocateCountsMap[attributeIdentifier]
|
|
if (exists == false){
|
|
return 0
|
|
}
|
|
return numberOfAttributeApproveAdvocates
|
|
}
|
|
|
|
if (approveWeight > 0 && banWeight == 0){
|
|
|
|
if (userIdentityType == "Mate" && attributeIsCanonical == false){
|
|
|
|
// The attribute must be approved by the minimum number of reviewers
|
|
numberOfAttributeApproveAdvocates := getNumberOfAttributeApproveAdvocates()
|
|
|
|
if (numberOfAttributeApproveAdvocates < minimumAttributeApproveAdvocates_Mate){
|
|
// Attribute status is Undecided
|
|
// The attribute is not approved by the minimum number of moderators.
|
|
nonCanonicalUndecidedExists = true
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
// approveWeight > 0 && banWeight > 0
|
|
|
|
// There is at least 1 ban on the attribute/profile
|
|
// We must make sure that the minimum number of approvers have approved the attribute
|
|
|
|
numberOfAttributeApproveAdvocates := getNumberOfAttributeApproveAdvocates()
|
|
if (numberOfAttributeApproveAdvocates < minimumNeededApprovers){
|
|
// The attribute has at least 1 ban advocate, and does not have the minimum required approve advocates.
|
|
return "Banned", nil
|
|
}
|
|
|
|
// We determine what the verdict is
|
|
|
|
approveRatio := approveWeight/banWeight
|
|
|
|
if (approveRatio < minimumApprovedRatio){
|
|
return "Banned", nil
|
|
}
|
|
// This attribute has passed. We continue to the next attribute
|
|
}
|
|
|
|
// All attributes are either approved or undecided
|
|
|
|
if (nonCanonicalUndecidedExists == true){
|
|
// Non-mate profiles do not need non-canonical attributes approved, if there are no ban reviews of the attribute
|
|
// For Mate profiles, all non-canonical attributes must be approved for the profile to be approved
|
|
return "Undecided", nil
|
|
}
|
|
|
|
// All attributes passed.
|
|
return "Approved", nil
|
|
}
|
|
|
|
verdictConsensus, err := getVerdictConsensus()
|
|
if (err != nil) { return false, false, 0, 0, [16]byte{}, nil, false, false, "", 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, 0, nil, nil, err }
|
|
|
|
return false, true, profileVersion, profileNetworkType, profileIdentityHash, profileAttributeHashesMap, true, true, verdictConsensus, numberOfEligibleApproveAdvocates, numberOfEligibleBanAdvocates, eligibleApproveAdvocateScoresSum, eligibleBanAdvocateScoresSum, eligibleAttributeApproveAdvocateCountsMap, eligibleAttributeBanAdvocateCountsMap, attributeApproveWeightsMap, attributeBanWeightsMap, allProfileApproveAdvocatesList, allProfileBanAdvocatesList, numberOfFullProfileBanAdvocates, allAttributeApproveAdvocatesMap, allAttributeBanAdvocatesMap, nil
|
|
}
|
|
|
|
|
|
//Outputs:
|
|
// -bool: Message metadata is known
|
|
// -int: Message version
|
|
// -byte: Message network type
|
|
// -[10]byte: Message inbox
|
|
// -[25]byte: Message cipher key hash
|
|
// -bool: Client is downloading required reviews and moderator profiles
|
|
// -bool: Parameters exist
|
|
// -string: Message verdict ("Approved"/"Banned"/"Undecided")
|
|
// -int: Number of eligible moderators who have approved the message
|
|
// -int: Number of eligible moderators who have banned the message
|
|
// -float64: Approve identity score sum (sum of identity scores of all eligible moderators who approved the message)
|
|
// -float64: Ban identity score sum (sum of identity scores of all eligible moderators who banned the message)
|
|
// -[][16]byte: List of approve advocates (eligible and banned)
|
|
// -[][16]byte: List of ban advocates (eligible and banned)
|
|
// -error
|
|
func GetVerifiedMessageVerdict(messageHash [26]byte)(bool, int, byte, [10]byte, [25]byte, bool, bool, string, int, int, float64, float64, [][16]byte, [][16]byte, error){
|
|
|
|
messageMetadataExists, messageVersion, messageNetworkType, _, messageInbox, messageCipherKeyHash, err := contentMetadata.GetMessageMetadata(messageHash)
|
|
if (err != nil) { return false, 0, 0, [10]byte{}, [25]byte{}, false, false, "", 0, 0, 0, 0, nil, nil, err }
|
|
if (messageMetadataExists == false){
|
|
|
|
// We do not know message metadata, so we cannot retrieve message moderated status
|
|
// Message must be downloaded at some point to get the message metadata
|
|
return false, 0, 0, [10]byte{}, [25]byte{}, false, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
|
|
clientIsDownloadingRequiredReviews, err := backgroundDownloads.CheckIfAppCanDetermineMessageVerdict(messageNetworkType, messageInbox, true, messageHash)
|
|
if (err != nil) { return false, 0, 0, [10]byte{}, [25]byte{}, false, false, "", 0, 0, 0, 0, nil, nil, err }
|
|
if (clientIsDownloadingRequiredReviews == false){
|
|
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, false, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
|
|
//TODO: Add parameters check
|
|
parametersExist := true
|
|
|
|
if (parametersExist == false){
|
|
// We do not have parameters downloaded. We cannot determine consensus verdict
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, true, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
|
|
approveAdvocatesMap, banAdvocatesMap, err := reviewStorage.GetMessageVerdictMaps(messageHash, messageNetworkType, messageCipherKeyHash)
|
|
if (err != nil) { return false, 0, 0, [10]byte{}, [25]byte{}, false, false, "", 0, 0, 0, 0, nil, nil, err }
|
|
if (len(approveAdvocatesMap) == 0 && len(banAdvocatesMap) == 0){
|
|
|
|
// There are no valid reviews for this message
|
|
|
|
emptyListA := make([][16]byte, 0)
|
|
emptyListB := make([][16]byte, 0)
|
|
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, true, true, "Undecided", 0, 0, 0, 0, emptyListA, emptyListB, nil
|
|
}
|
|
|
|
getEnabledModeratorsFromMap := func(inputModeratorsMap map[[16]byte]int64)([][16]byte, error){
|
|
|
|
enabledModeratorsList := make([][16]byte, 0)
|
|
|
|
for moderatorIdentityHash, _ := range inputModeratorsMap{
|
|
|
|
moderatorIsEnabled, err := enabledModerators.CheckIfModeratorIsEnabled(true, moderatorIdentityHash, messageNetworkType)
|
|
if (err != nil){ return nil, err }
|
|
if (moderatorIsEnabled == false){
|
|
// We will disregard all of this moderators reviews
|
|
continue
|
|
}
|
|
|
|
enabledModeratorsList = append(enabledModeratorsList, moderatorIdentityHash)
|
|
}
|
|
|
|
return enabledModeratorsList, nil
|
|
}
|
|
|
|
allEnabledApproveAdvocatesList, err := getEnabledModeratorsFromMap(approveAdvocatesMap)
|
|
if (err != nil){ return false, 0, 0, [10]byte{}, [25]byte{}, false, false, "", 0, 0, 0, 0, nil, nil, err }
|
|
|
|
allEnabledBanAdvocatesList, err := getEnabledModeratorsFromMap(banAdvocatesMap)
|
|
if (err != nil){ return false, 0, 0, [10]byte{}, [25]byte{}, false, false, "", 0, 0, 0, 0, nil, nil, err }
|
|
|
|
//Outputs:
|
|
// -bool: Downloading required data
|
|
// -bool: Parameters exist
|
|
// -int: Number of eligible moderators
|
|
// -float64: Sum of all moderator scores
|
|
// -error
|
|
getEligibleModeratorsCountAndScoresSum := func(inputModeratorsList [][16]byte)(bool, bool, int, float64, error){
|
|
|
|
numberOfEligibleModerators := 0
|
|
eligibleModeratorScoresSum := float64(0)
|
|
|
|
for _, moderatorIdentityHash := range inputModeratorsList{
|
|
|
|
downloadingRequiredData, parametersExist, moderatorIsBanned, err := bannedModeratorConsensus.GetModeratorIsBannedStatus(true, moderatorIdentityHash, messageNetworkType)
|
|
if (err != nil) { return false, false, 0, 0, err }
|
|
if (downloadingRequiredData == false){
|
|
return false, false, 0, 0, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return false, true, 0, 0, nil
|
|
}
|
|
if (moderatorIsBanned == true){
|
|
continue
|
|
}
|
|
|
|
scoreIsKnown, moderatorScore, scoreIsSufficient, _, _, err := moderatorScores.GetModeratorIdentityScore(moderatorIdentityHash)
|
|
if (err != nil) { return false, false, 0, 0, err }
|
|
if (scoreIsKnown == false || scoreIsSufficient == false){
|
|
continue
|
|
}
|
|
|
|
numberOfEligibleModerators += 1
|
|
eligibleModeratorScoresSum += moderatorScore
|
|
}
|
|
|
|
return true, true, numberOfEligibleModerators, eligibleModeratorScoresSum, nil
|
|
}
|
|
|
|
downloadingRequiredData, parametersExist, numberOfEligibleApproveAdvocates, eligibleApproveAdvocatesScoreSum, err := getEligibleModeratorsCountAndScoresSum(allEnabledApproveAdvocatesList)
|
|
if (downloadingRequiredData == false){
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, false, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, true, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
|
|
downloadingRequiredData, parametersExist, numberOfEligibleBanAdvocates, eligibleBanAdvocatesScoreSum, err := getEligibleModeratorsCountAndScoresSum(allEnabledBanAdvocatesList)
|
|
if (downloadingRequiredData == false){
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, false, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
if (parametersExist == false){
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, true, false, "", 0, 0, 0, 0, nil, nil, nil
|
|
}
|
|
|
|
getMessageVerdictConsensus := func()string{
|
|
|
|
//TODO: Fix this to use parameters
|
|
minimumBanAdvocatesCount := 3
|
|
minimumApproveAdvocatesCount := 3
|
|
|
|
if (numberOfEligibleBanAdvocates < minimumBanAdvocatesCount){
|
|
return "Undecided"
|
|
}
|
|
|
|
if (eligibleApproveAdvocatesScoreSum < eligibleBanAdvocatesScoreSum){
|
|
return "Banned"
|
|
}
|
|
if (numberOfEligibleApproveAdvocates >= minimumApproveAdvocatesCount){
|
|
return "Approved"
|
|
}
|
|
|
|
return "Undecided"
|
|
}
|
|
|
|
messageVerdictConsensus := getMessageVerdictConsensus()
|
|
|
|
return true, messageVersion, messageNetworkType, messageInbox, messageCipherKeyHash, true, true, messageVerdictConsensus, numberOfEligibleApproveAdvocates, numberOfEligibleBanAdvocates, eligibleApproveAdvocatesScoreSum, eligibleBanAdvocatesScoreSum, allEnabledApproveAdvocatesList, allEnabledBanAdvocatesList, nil
|
|
}
|
|
|
|
|
|
|