public static async Task <ValidationResult> ValidateConsensusAfterExecutionAsync( this ContractTester <DPoSSideChainTestAElfModule> tester, DPoSHeaderInformation information) { var bytes = await tester.CallContractMethodAsync(tester.GetConsensusContractAddress(), ConsensusConsts.ValidateConsensusAfterExecution, information); return(ValidationResult.Parser.ParseFrom(bytes)); }
public async Task Validation_ConsensusAfterExecution_Success() { TesterManager.InitialTesters(); var dposInformation = new DPoSHeaderInformation(); var validationResult = await TesterManager.Testers[0].ValidateConsensusAfterExecutionAsync(dposInformation); validationResult.Success.ShouldBeTrue(); }
public async Task UpdateMainChainConsensus_WithDefaultDPosInformation() { TesterManager.InitialTesters(); //input = new DPoSInformation() var dposInformation = new DPoSHeaderInformation(); var transactionResult = await TesterManager.Testers[0].ExecuteContractWithMiningAsync( TesterManager.DPoSSideChainContractAddress, "UpdateMainChainConsensus", dposInformation); transactionResult.Status.ShouldBe(TransactionResultStatus.Mined); }
public async Task Validation_ConsensusBeforeExecution_Success() { TesterManager.InitialTesters(); //invalid dpos header info { var invalidInput = new DPoSHeaderInformation { SenderPublicKey = ByteString.CopyFrom(TesterManager.Testers[0].KeyPair.PublicKey) }; var validationResult = await TesterManager.Testers[0].ValidateConsensusBeforeExecutionAsync(invalidInput); validationResult.Success.ShouldBeFalse(); } await InitialConsensus_Success(); var roundInfo = await TesterManager.Testers[0].GetCurrentRoundInformation(); var input = new DPoSHeaderInformation { SenderPublicKey = ByteString.CopyFrom(TesterManager.Testers[0].KeyPair.PublicKey), Round = roundInfo, Behaviour = DPoSBehaviour.Nothing }; //invalid behavior { var validationResult = await TesterManager.Testers[0].ValidateConsensusBeforeExecutionAsync(input); validationResult.Success.ShouldBeFalse(); validationResult.Message.ShouldBe("Invalid behaviour"); } //invalid out value { input.Behaviour = DPoSBehaviour.UpdateValue; var validationResult = await TesterManager.Testers[0].ValidateConsensusBeforeExecutionAsync(input); validationResult.Success.ShouldBeFalse(); validationResult.Message.ShouldBe("Incorrect new Out Value."); } //valid data { input.Behaviour = DPoSBehaviour.NextRound; var validationResult = await TesterManager.Testers[0].ValidateConsensusBeforeExecutionAsync(input); validationResult.Success.ShouldBeTrue(); input.Behaviour = DPoSBehaviour.NextTerm; validationResult = await TesterManager.Testers[0].ValidateConsensusBeforeExecutionAsync(input); validationResult.Success.ShouldBeTrue(); } }
public async Task NormalBlock_ValidateConsensusAfterExecution_Success() { var startTime = DateTime.UtcNow.ToTimestamp(); var testers = new ConsensusTesters(); testers.InitialTesters(startTime); var newInformation = new DPoSHeaderInformation { SenderPublicKey = ByteString.CopyFrom(testers.Testers[0].KeyPair.PublicKey), Round = await testers.Testers[0].GetCurrentRoundInformationAsync(), Behaviour = DPoSBehaviour.UpdateValueWithoutPreviousInValue }; // Act var validationResult = await testers.Testers[0].ValidateConsensusAfterExecutionAsync(newInformation); validationResult.Success.ShouldBeTrue(); }
public override ValidationResult ValidateConsensusAfterExecution(DPoSHeaderInformation input) { if (TryToGetCurrentRoundInformation(out var currentRound)) { var isContainPreviousInValue = input.Behaviour != DPoSBehaviour.UpdateValueWithoutPreviousInValue; if (input.Round.GetHash(isContainPreviousInValue) != currentRound.GetHash(isContainPreviousInValue)) { Context.LogDebug(() => $"Round information of block header:\n{input.Round}"); Context.LogDebug(() => $"Round information of executing result:\n{currentRound}"); return(new ValidationResult { Success = false, Message = "Current round information is different with consensus extra data." }); } } return(new ValidationResult { Success = true }); }
public async Task UpdateMainChainConsensus_FirstRoundInfo() { TesterManager.InitialTesters(); var dposInformation = new DPoSHeaderInformation { Behaviour = DPoSBehaviour.NextRound, Round = TesterManager.MinersKeyPairs.Select(p => p.PublicKey.ToHex()).ToList().ToMiners() .GenerateFirstRoundOfNewTerm(DPoSSideChainTester.MiningInterval, DateTime.UtcNow), SenderPublicKey = ByteString.CopyFrom(TesterManager.MinersKeyPairs[0].PublicKey) }; var transactionResult = await TesterManager.Testers[0].ExecuteContractWithMiningAsync( TesterManager.DPoSSideChainContractAddress, "UpdateMainChainConsensus", new ConsensusInformation { Bytes = dposInformation.ToByteString() }); transactionResult.Status.ShouldBe(TransactionResultStatus.Mined); }
public async Task NormalBlock_ValidateConsensusBeforeExecution_Success() { var startTime = DateTime.UtcNow.ToTimestamp(); var testers = new ConsensusTesters(); testers.InitialTesters(startTime); var currentRound = await testers.Testers[0].GetCurrentRoundInformationAsync(); var roundInfo = new Round { BlockchainAge = currentRound.BlockchainAge + 1, RoundNumber = currentRound.RoundNumber + 1, TermNumber = currentRound.TermNumber, RealTimeMinersInformation = { { testers.Testers[0].PublicKey, new MinerInRound { OutValue = Hash.Generate(), FinalOrderOfNextRound = 1, ExpectedMiningTime = currentRound.RealTimeMinersInformation[testers.Testers[0].PublicKey].ExpectedMiningTime, Order = 1 } }, { testers.Testers[1].PublicKey, new MinerInRound { OutValue = Hash.Generate(), FinalOrderOfNextRound = 2, ExpectedMiningTime = currentRound.RealTimeMinersInformation[testers.Testers[1].PublicKey].ExpectedMiningTime, Order = 2 } }, { testers.Testers[2].PublicKey, new MinerInRound { OutValue = Hash.Generate(), FinalOrderOfNextRound = 3, ExpectedMiningTime = currentRound.RealTimeMinersInformation[testers.Testers[2].PublicKey].ExpectedMiningTime, Order = 3 } }, } }; var newInformation = new DPoSHeaderInformation { SenderPublicKey = ByteString.CopyFrom(testers.Testers[0].KeyPair.PublicKey), Round = roundInfo, Behaviour = DPoSBehaviour.NextRound }; // Act var validationResult = await testers.Testers[0].ValidateConsensusBeforeExecutionAsync(newInformation); validationResult.Success.ShouldBeTrue(); //nothing behavior newInformation.Behaviour = DPoSBehaviour.Nothing; validationResult = await testers.Testers[0].ValidateConsensusBeforeExecutionAsync(newInformation); validationResult.Success.ShouldBeFalse(); validationResult.Message.ShouldBe("Invalid behaviour"); //update value newInformation.Behaviour = DPoSBehaviour.UpdateValue; validationResult = await testers.Testers[0].ValidateConsensusBeforeExecutionAsync(newInformation); validationResult.ShouldNotBeNull(); }
public override DPoSHeaderInformation GetInformationToUpdateConsensus(DPoSTriggerInformation input) { // Some basic checks. Assert(input.PublicKey.Any(), "Invalid public key."); var publicKey = input.PublicKey; var currentBlockTime = Context.CurrentBlockTime; var behaviour = input.Behaviour; Assert(TryToGetCurrentRoundInformation(out var currentRound), ContractErrorCode.GetErrorMessage(ContractErrorCode.AttemptFailed, "Failed to get current round information.")); switch (behaviour) { case DPoSBehaviour.UpdateValueWithoutPreviousInValue: case DPoSBehaviour.UpdateValue: Assert(input.RandomHash != null, "Random hash should not be null."); var inValue = currentRound.CalculateInValue(input.RandomHash); var outValue = Hash.FromMessage(inValue); var signature = Hash.FromTwoHashes(outValue, input.RandomHash); // Just initial signature value. var previousInValue = Hash.Empty; // Just initial previous in value. if (TryToGetPreviousRoundInformation(out var previousRound) && !IsJustChangedTerm(out _)) { signature = previousRound.CalculateSignature(inValue); LogVerbose($"Previous random hash: {input.PreviousRandomHash.ToHex()}"); if (input.PreviousRandomHash != Hash.Empty) { // If PreviousRandomHash is Hash.Empty, it means the sender unable or unwilling to publish his previous in value. previousInValue = previousRound.CalculateInValue(input.PreviousRandomHash); } } var updatedRound = currentRound.ApplyNormalConsensusData(publicKey.ToHex(), previousInValue, outValue, signature, currentBlockTime); ShareAndRecoverInValue(updatedRound, previousRound, inValue, publicKey.ToHex()); // To publish Out Value. return(new DPoSHeaderInformation { SenderPublicKey = publicKey, Round = updatedRound, Behaviour = behaviour, }); case DPoSBehaviour.NextRound: Assert( GenerateNextRoundInformation(currentRound, currentBlockTime, out var nextRound), "Failed to generate next round information."); nextRound.RealTimeMinersInformation[publicKey.ToHex()].ProducedBlocks += 1; Context.LogDebug(() => $"Mined blocks: {nextRound.GetMinedBlocks()}"); nextRound.ExtraBlockProducerOfPreviousRound = publicKey.ToHex(); return(new DPoSHeaderInformation { SenderPublicKey = publicKey, Round = nextRound, Behaviour = behaviour }); case DPoSBehaviour.NextTerm: var firstRoundOfNextTerm = GenerateFirstRoundOfNextTerm(publicKey.ToHex()); Assert(firstRoundOfNextTerm.RoundId != 0, "Failed to generate new round information."); var information = new DPoSHeaderInformation { SenderPublicKey = publicKey, Round = firstRoundOfNextTerm, Behaviour = behaviour }; return(information); default: return(new DPoSHeaderInformation()); } }
public override ValidationResult ValidateConsensusBeforeExecution(DPoSHeaderInformation input) { var publicKey = input.SenderPublicKey; // Validate the sender. if (TryToGetCurrentRoundInformation(out var currentRound) && !currentRound.RealTimeMinersInformation.ContainsKey(publicKey.ToHex())) { return(new ValidationResult { Success = false, Message = "Sender is not a miner." }); } // Validate the time slots. var timeSlotsCheckResult = input.Round.CheckTimeSlots(); if (!timeSlotsCheckResult.Success) { return(timeSlotsCheckResult); } var behaviour = input.Behaviour; // Try to get current round information (for further validation). if (currentRound == null) { return(new ValidationResult { Success = false, Message = "Failed to get current round information." }); } if (input.Round.RealTimeMinersInformation.Values.Where(m => m.FinalOrderOfNextRound > 0).Distinct() .Count() != input.Round.RealTimeMinersInformation.Values.Count(m => m.OutValue != null)) { return(new ValidationResult { Success = false, Message = "Invalid FinalOrderOfNextRound." }); } switch (behaviour) { case DPoSBehaviour.UpdateValueWithoutPreviousInValue: case DPoSBehaviour.UpdateValue: // Need to check round id when updating current round information. // This can tell the miner current block if (!RoundIdMatched(input.Round)) { return(new ValidationResult { Success = false, Message = "Round Id not match." }); } // Only one Out Value should be filled. // TODO: Miner can only update his information. if (!NewOutValueFilled(input.Round.RealTimeMinersInformation.Values)) { return(new ValidationResult { Success = false, Message = "Incorrect new Out Value." }); } break; case DPoSBehaviour.NextRound: // None of in values should be filled. if (!InValueIsNull(input.Round)) { return(new ValidationResult { Success = false, Message = "Incorrect in values." }); } break; case DPoSBehaviour.NextTerm: break; case DPoSBehaviour.Nothing: return(new ValidationResult { Success = false, Message = "Invalid behaviour" }); default: throw new ArgumentOutOfRangeException(); } return(new ValidationResult { Success = true }); }