public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { var validationResult = new ValidationResult(); // If provided round is a new round if (validationContext.ProvidedRound.RoundId != validationContext.BaseRound.RoundId) { // Is new round information fits time slot rule? validationResult = validationContext.ProvidedRound.CheckRoundTimeSlots(); if (!validationResult.Success) { return(validationResult); } } else { // Is sender respect his time slot? // It is maybe failing due to using too much time producing previous tiny blocks. if (!CheckMinerTimeSlot(validationContext)) { validationResult.Message = $"Time slot already passed before execution.{validationContext.SenderPubkey}"; validationResult.IsReTrigger = true; return(validationResult); } } validationResult.Success = true; return(validationResult); }
private bool ValidatePreviousInValue(ConsensusValidationContext validationContext) { var extraData = validationContext.ExtraData; var publicKey = validationContext.SenderPubkey; if (!validationContext.PreviousRound.RealTimeMinersInformation.ContainsKey(publicKey)) { return(true); } if (extraData.Round.RealTimeMinersInformation[publicKey].PreviousInValue == null) { return(true); } var previousOutValue = validationContext.PreviousRound.RealTimeMinersInformation[publicKey].OutValue; var previousInValue = extraData.Round.RealTimeMinersInformation[publicKey].PreviousInValue; if (previousInValue == Hash.Empty) { return(true); } return(Hash.FromMessage(previousInValue) == previousOutValue); }
private bool CheckMinerTimeSlot(ConsensusValidationContext validationContext) { if (IsFirstRoundOfCurrentTerm(out _, validationContext)) { return(true); } var minerInRound = validationContext.BaseRound.RealTimeMinersInformation[validationContext.SenderPubkey]; var latestActualMiningTime = minerInRound.ActualMiningTimes.OrderBy(t => t).LastOrDefault(); if (latestActualMiningTime == null) { return(true); } var expectedMiningTime = minerInRound.ExpectedMiningTime; var endOfExpectedTimeSlot = expectedMiningTime.AddMilliseconds(validationContext.BaseRound.GetMiningInterval()); if (latestActualMiningTime < expectedMiningTime) { // Which means this miner is producing tiny blocks for previous extra block slot. return(latestActualMiningTime < validationContext.BaseRound.GetRoundStartTime()); } return(latestActualMiningTime < endOfExpectedTimeSlot); }
public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { var validationResult = new ValidationResult(); var baseRound = validationContext.BaseRound; var providedRound = validationContext.ProvidedRound; var pubkey = validationContext.SenderPubkey; if (providedRound.ConfirmedIrreversibleBlockHeight != 0 && providedRound.ConfirmedIrreversibleBlockRoundNumber != 0 && (baseRound.ConfirmedIrreversibleBlockHeight > providedRound.ConfirmedIrreversibleBlockHeight || baseRound.ConfirmedIrreversibleBlockRoundNumber > providedRound.ConfirmedIrreversibleBlockRoundNumber)) { validationResult.Message = "Incorrect lib information.\n" + $"{baseRound.ConfirmedIrreversibleBlockHeight} > {providedRound.ConfirmedIrreversibleBlockHeight}\n" + $"{baseRound.ConfirmedIrreversibleBlockRoundNumber} > {providedRound.ConfirmedIrreversibleBlockRoundNumber}"; return(validationResult); } if (providedRound.RealTimeMinersInformation.ContainsKey(pubkey) && providedRound.RealTimeMinersInformation[pubkey].ImpliedIrreversibleBlockHeight != 0 && baseRound.RealTimeMinersInformation[pubkey].ImpliedIrreversibleBlockHeight > providedRound.RealTimeMinersInformation[pubkey].ImpliedIrreversibleBlockHeight) { validationResult.Message = "Incorrect implied lib height."; return(validationResult); } validationResult.Success = true; return(validationResult); }
private bool ValidateProducedBlocksCount(ConsensusValidationContext validationContext) { var pubkey = validationContext.SenderPubkey; return(validationContext.BaseRound.RealTimeMinersInformation[pubkey].ProducedBlocks.Add(1) == validationContext.ProvidedRound.RealTimeMinersInformation[pubkey].ProducedBlocks); }
/// <summary> /// Check only one Out Value was filled during this updating. /// </summary> /// <param name="validationContext"></param> /// <returns></returns> private bool NewConsensusInformationFilled(ConsensusValidationContext validationContext) { var minerInRound = validationContext.ProvidedRound.RealTimeMinersInformation[validationContext.SenderPubkey]; return(minerInRound.OutValue != null && minerInRound.Signature != null && minerInRound.OutValue.Value.Any() && minerInRound.Signature.Value.Any()); }
/// <summary> /// This validation will based on current round information stored in StateDb. /// Simply check keys of RealTimeMinersInformation should be enough. /// </summary> /// <param name="validationContext"></param> /// <returns></returns> public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { var validationResult = new ValidationResult(); if (!validationContext.BaseRound.RealTimeMinersInformation.Keys.Contains(validationContext.SenderPubkey)) { validationResult.Message = $"Sender {validationContext.SenderPubkey} is not a miner."; return(validationResult); } validationResult.Success = true; return(validationResult); }
public ValidationResult ValidateInformation(ConsensusValidationContext validationContext) { foreach (var headerInformationValidationProvider in _headerInformationValidationProviders) { var result = headerInformationValidationProvider.ValidateHeaderInformation(validationContext); if (!result.Success) { return(result); } } return(new ValidationResult { Success = true }); }
public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { // Miners that have determined the order of the next round should be equal to // miners that mined blocks during current round. var validationResult = new ValidationResult(); var providedRound = validationContext.ProvidedRound; if (providedRound.RealTimeMinersInformation.Values.Where(m => m.FinalOrderOfNextRound > 0).Distinct() .Count() != providedRound.RealTimeMinersInformation.Values.Count(m => m.OutValue != null)) { validationResult.Message = "Invalid FinalOrderOfNextRound."; return(validationResult); } validationResult.Success = true; return(validationResult); }
public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { var validationResult = new ValidationResult(); var extraData = validationContext.ExtraData; switch (extraData.Behaviour) { case AElfConsensusBehaviour.NextRound: return(ValidationForNextRound(validationContext)); case AElfConsensusBehaviour.NextTerm: return(ValidationForNextTerm(validationContext)); default: validationResult.Success = true; return(validationResult); } }
private ValidationResult ValidationForNextTerm(ConsensusValidationContext validationContext) { var extraData = validationContext.ExtraData; var validationResult = ValidationForNextRound(validationContext); if (!validationResult.Success) { return(validationResult); } // Is next term number correct? return(validationContext.BaseRound.TermNumber.Add(1) != extraData.Round.TermNumber ? new ValidationResult { Message = "Incorrect term number for next round." } : new ValidationResult { Success = true }); }
public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { // Only one Out Value should be filled. if (!NewConsensusInformationFilled(validationContext)) { return(new ValidationResult { Message = "Incorrect new Out Value." }); } if (!ValidatePreviousInValue(validationContext)) { return(new ValidationResult { Message = "Incorrect previous in value." }); } return(new ValidationResult { Success = true }); }
public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { // Need to check round id when updating current round information. if (!IsRoundIdMatched(validationContext)) { return(new ValidationResult { Message = "Round Id not match." }); } if (!ValidateProducedBlocksCount(validationContext)) { return(new ValidationResult { Message = "Incorrect produced blocks count." }); } return(new ValidationResult { Success = true }); }
public ValidationResult ValidateHeaderInformation(ConsensusValidationContext validationContext) { // Is sender produce too many continuous blocks? var validationResult = new ValidationResult(); if (validationContext.ProvidedRound.RoundNumber > 2 && // Skip first two rounds. validationContext.BaseRound.RealTimeMinersInformation.Count != 1) { var latestPubkeyToTinyBlocksCount = validationContext.LatestPubkeyToTinyBlocksCount; if (latestPubkeyToTinyBlocksCount != null && latestPubkeyToTinyBlocksCount.Pubkey == validationContext.SenderPubkey && latestPubkeyToTinyBlocksCount.BlocksCount < 0) { validationResult.Message = "Sender produced too many continuous blocks."; return(validationResult); } } validationResult.Success = true; return(validationResult); }
private ValidationResult ValidationForNextRound(ConsensusValidationContext validationContext) { // Is next round information correct? // Currently two aspects: // Round Number // In Values Should Be Null var extraData = validationContext.ExtraData; if (validationContext.BaseRound.RoundNumber.Add(1) != extraData.Round.RoundNumber) { return(new ValidationResult { Message = "Incorrect round number for next round." }); } return(extraData.Round.RealTimeMinersInformation.Values.Any(m => m.InValue != null) ? new ValidationResult { Message = "Incorrect next round information." } : new ValidationResult { Success = true }); }
private bool IsFirstRoundOfCurrentTerm(out long termNumber, ConsensusValidationContext validationContext) { termNumber = validationContext.CurrentTermNumber; return(validationContext.PreviousRound.TermNumber != termNumber || validationContext.CurrentRoundNumber == 1); }
private bool IsRoundIdMatched(ConsensusValidationContext validationContext) { return(validationContext.BaseRound.RoundId == validationContext.ProvidedRound.RoundIdForValidation); }