/// <summary> /// Generate encrypted messages and put them to round information. /// </summary> /// <returns></returns> private async Task <Dictionary <string, AElfConsensusTriggerInformation> > GenerateEncryptedMessagesAsync() { var firstRound = await AEDPoSContractStub.GetCurrentRoundInformation.CallAsync(new Empty()); var randomHashes = Enumerable.Range(0, EconomicContractsTestConstants.InitialCoreDataCenterCount) .Select(_ => Hash.FromString("randomHashes")).ToList(); var triggers = Enumerable.Range(0, EconomicContractsTestConstants.InitialCoreDataCenterCount).Select(i => new AElfConsensusTriggerInformation { Pubkey = ByteString.CopyFrom(InitialCoreDataCenterKeyPairs[i].PublicKey), InValue = randomHashes[i] }).ToDictionary(t => t.Pubkey.ToHex(), t => t); foreach (var minerInRound in firstRound.RealTimeMinersInformation.Values.OrderBy(m => m.Order)) { var currentKeyPair = InitialCoreDataCenterKeyPairs.First(p => p.PublicKey.ToHex() == minerInRound.Pubkey); KeyPairProvider.SetKeyPair(currentKeyPair); BlockTimeProvider.SetBlockTime(minerInRound.ExpectedMiningTime); var tester = GetAEDPoSContractStub(currentKeyPair); var headerInformation = new AElfConsensusHeaderInformation(); headerInformation.MergeFrom( (await AEDPoSContractStub.GetConsensusExtraData.CallAsync(triggers[minerInRound.Pubkey] .ToBytesValue())).Value); // Update consensus information. var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.Pubkey); await tester.UpdateValue.SendAsync(toUpdate); } return(triggers); }
internal static AElfConsensusHeaderInformation ToConsensusHeaderInformation(this BytesValue bytesValue) { var headerInformation = new AElfConsensusHeaderInformation(); headerInformation.MergeFrom(bytesValue.Value); return(headerInformation); }
private ValidationResult ValidationForUpdateValue(AElfConsensusHeaderInformation extraData) { // Need to check round id when updating current round information. if (!IsRoundIdMatched(extraData.Round)) { return(new ValidationResult { Message = "Round Id not match." }); } // Only one Out Value should be filled. if (!NewOutValueFilled(extraData.Round.RealTimeMinersInformation.Values)) { return(new ValidationResult { Message = "Incorrect new Out Value." }); } if (!ValidatePreviousInValue(extraData)) { return(new ValidationResult { Message = "Incorrect previous in value." }); } return(new ValidationResult { Success = true }); }
private bool ValidatePreviousInValue(AElfConsensusHeaderInformation extraData) { var publicKey = extraData.SenderPubkey.ToHex(); if (!TryToGetPreviousRoundInformation(out var previousRound)) { return(true); } if (!previousRound.RealTimeMinersInformation.ContainsKey(publicKey)) { return(true); } if (extraData.Round.RealTimeMinersInformation[publicKey].PreviousInValue == null) { return(true); } var previousOutValue = previousRound.RealTimeMinersInformation[publicKey].OutValue; var previousInValue = extraData.Round.RealTimeMinersInformation[publicKey].PreviousInValue; if (previousInValue == Hash.Empty) { return(true); } return(Hash.FromMessage(previousInValue) == previousOutValue); }
private TransactionList GenerateTransactionListByExtraData(AElfConsensusHeaderInformation consensusInformation, ByteString pubkey) { var round = consensusInformation.Round; var behaviour = consensusInformation.Behaviour; switch (behaviour) { case AElfConsensusBehaviour.UpdateValue: Context.LogDebug(() => $"Previous in value in extra data:{round.RealTimeMinersInformation[pubkey.ToHex()].PreviousInValue}"); return(new TransactionList { Transactions = { GenerateTransaction(nameof(UpdateValue), round.ExtractInformationToUpdateConsensus(pubkey.ToHex())) } }); case AElfConsensusBehaviour.TinyBlock: var minerInRound = round.RealTimeMinersInformation[pubkey.ToHex()]; return(new TransactionList { Transactions = { GenerateTransaction(nameof(UpdateTinyBlockInformation), new TinyBlockInput { ActualMiningTime = minerInRound.ActualMiningTimes.Last(), ProducedBlocks = minerInRound.ProducedBlocks, RoundId = round.RoundIdForValidation }) } }); case AElfConsensusBehaviour.NextRound: return(new TransactionList { Transactions = { GenerateTransaction(nameof(NextRound), round) } }); case AElfConsensusBehaviour.NextTerm: return(new TransactionList { Transactions = { GenerateTransaction(nameof(NextTerm), round) } }); default: return(new TransactionList()); } }
private ValidationResult ValidateBeforeExecution(AElfConsensusHeaderInformation extraData) { var publicKey = extraData.SenderPubkey.ToHex(); var updatedRound = extraData.Round; // Validate the sender. if (TryToGetCurrentRoundInformation(out var currentRound) && !currentRound.RealTimeMinersInformation.ContainsKey(publicKey)) { Context.LogDebug(() => "Sender is not a miner."); return(new ValidationResult { Success = false, Message = $"Sender {publicKey} is not a miner." }); } // Validate the time slots of round information. var timeSlotsCheckResult = updatedRound.CheckRoundTimeSlots(); if (!timeSlotsCheckResult.Success) { Context.LogDebug(() => $"Round time slots incorrect: {timeSlotsCheckResult.Message}"); return(timeSlotsCheckResult); } // Validate whether this miner abide by his time slot. // Maybe failing due to using too much time producing previous tiny blocks. if (updatedRound.RoundId == currentRound.RoundId && !CheckMinerTimeSlot(updatedRound, publicKey)) { Context.LogDebug(() => "Time slot already passed before execution."); return(new ValidationResult { Message = "Time slot already passed before execution." }); } if (updatedRound.RealTimeMinersInformation.Values.Where(m => m.FinalOrderOfNextRound > 0).Distinct() .Count() != updatedRound.RealTimeMinersInformation.Values.Count(m => m.OutValue != null)) { return(new ValidationResult { Message = "Invalid FinalOrderOfNextRound." }); } switch (extraData.Behaviour) { case AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue: case AElfConsensusBehaviour.UpdateValue: return(ValidationForUpdateValue(extraData)); case AElfConsensusBehaviour.NextRound: return(ValidationForNextRound(extraData)); } return(new ValidationResult { Success = true }); }
private BytesValue GetConsensusBlockExtraData(BytesValue input, bool isGeneratingTransactions = false) { var triggerInformation = new AElfConsensusTriggerInformation(); triggerInformation.MergeFrom(input.Value); Assert(triggerInformation.Pubkey.Any(), "Invalid pubkey."); if (!TryToGetCurrentRoundInformation(out var currentRound)) { Assert(false, "Failed to get current round information."); } var publicKeyBytes = triggerInformation.Pubkey; var pubkey = publicKeyBytes.ToHex(); LogIfPreviousMinerHasNotProduceEnoughTinyBlocks(currentRound, pubkey); var information = new AElfConsensusHeaderInformation(); switch (triggerInformation.Behaviour) { case AElfConsensusBehaviour.UpdateValue: information = GetConsensusExtraDataToPublishOutValue(currentRound, pubkey, triggerInformation); if (!isGeneratingTransactions) { information.Round = information.Round.GetUpdateValueRound(pubkey); } break; case AElfConsensusBehaviour.TinyBlock: information = GetConsensusExtraDataForTinyBlock(currentRound, pubkey, triggerInformation); break; case AElfConsensusBehaviour.NextRound: information = GetConsensusExtraDataForNextRound(currentRound, pubkey, triggerInformation); break; case AElfConsensusBehaviour.NextTerm: information = GetConsensusExtraDataForNextTerm(pubkey, triggerInformation); break; } if (!isGeneratingTransactions) { information.Round.DeleteSecretSharingInformation(); } return(information.ToBytesValue()); }
private ValidationResult ValidationForNextRound(AElfConsensusHeaderInformation extraData) { // None of in values should be filled. if (extraData.Round.RealTimeMinersInformation.Values.Any(m => m.InValue != null)) { return(new ValidationResult { Message = "Incorrect in values." }); } return(new ValidationResult { Success = true }); }
public override TransactionList GenerateConsensusTransactions(BytesValue input) { var triggerInformation = new AElfConsensusTriggerInformation(); triggerInformation.MergeFrom(input.Value); // Some basic checks. Assert(triggerInformation.Pubkey.Any(), "Data to request consensus information should contain pubkey."); var pubkey = triggerInformation.Pubkey; var consensusInformation = new AElfConsensusHeaderInformation(); consensusInformation.MergeFrom(GetConsensusBlockExtraData(input, true).Value); var transactionList = GenerateTransactionListByExtraData(consensusInformation, pubkey); return(transactionList); }
public async Task DecryptMessage_Test() { var previousTriggers = await GenerateEncryptedMessagesAsync(); await BootMinerChangeRoundAsync(); var currentRound = await AEDPoSContractStub.GetCurrentRoundInformation.CallAsync(new Empty()); var randomHashes = Enumerable.Range(0, EconomicContractsTestConstants.InitialCoreDataCenterCount) .Select(_ => Hash.FromString("randomHashes")).ToList(); var triggers = Enumerable.Range(0, EconomicContractsTestConstants.InitialCoreDataCenterCount).Select(i => new AElfConsensusTriggerInformation { Pubkey = ByteString.CopyFrom(InitialCoreDataCenterKeyPairs[i].PublicKey), RandomHash = randomHashes[i], PreviousRandomHash = previousTriggers[InitialCoreDataCenterKeyPairs[i].PublicKey.ToHex()].RandomHash }).ToDictionary(t => t.Pubkey.ToHex(), t => t); // Just `MinimumCount + 1` miners produce blocks. foreach (var minerInRound in currentRound.RealTimeMinersInformation.Values.OrderBy(m => m.Order) .Take(MinimumCount + 1)) { var currentKeyPair = InitialCoreDataCenterKeyPairs.First(p => p.PublicKey.ToHex() == minerInRound.Pubkey); KeyPairProvider.SetKeyPair(currentKeyPair); BlockTimeProvider.SetBlockTime(minerInRound.ExpectedMiningTime); var tester = GetAEDPoSContractStub(currentKeyPair); var headerInformation = new AElfConsensusHeaderInformation(); headerInformation.MergeFrom( (await AEDPoSContractStub.GetInformationToUpdateConsensus.CallAsync(triggers[minerInRound.Pubkey] .ToBytesValue())).Value); // Update consensus information. var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.Pubkey); await tester.UpdateValue.SendAsync(toUpdate); } // Won't pass because currently we postpone the revealing of in values to extra block time slot. // But in values all filled. // var secondRound = await BootMiner.GetCurrentRoundInformation.CallAsync(new Empty()); // secondRound.RealTimeMinersInformation.Values.Count(v => v.PreviousInValue != null) // .ShouldBe(AEDPoSContractTestConstants.InitialMinersCount); }
private ValidationResult ValidationForNextTerm(AElfConsensusHeaderInformation extraData) { // Is next round information correct? var validationResult = ValidationForNextRound(extraData); if (!validationResult.Success) { return(validationResult); } if (TryToGetCurrentRoundInformation(out var currentRound, true) && currentRound.TermNumber.Add(1) != extraData.Round.TermNumber) { return(new ValidationResult { Message = "Incorrect term number for next round." }); } return(new ValidationResult { Success = true }); }
private ValidationResult ValidationForNextRound(AElfConsensusHeaderInformation extraData) { // Is next round information correct? if (TryToGetCurrentRoundInformation(out var currentRound, true) && currentRound.RoundNumber.Add(1) != extraData.Round.RoundNumber) { return(new ValidationResult { Message = "Incorrect round number for next round." }); } if (extraData.Round.RealTimeMinersInformation.Values.Any(m => m.InValue != null)) { return(new ValidationResult { Message = "Incorrect next round information." }); } return(new ValidationResult { Success = true }); }
public override ValidationResult ValidateConsensusAfterExecution(BytesValue input) { var headerInformation = new AElfConsensusHeaderInformation(); headerInformation.MergeFrom(input.Value); if (TryToGetCurrentRoundInformation(out var currentRound)) { if (headerInformation.Behaviour == AElfConsensusBehaviour.UpdateValue) { headerInformation.Round = currentRound.RecoverFromUpdateValue(headerInformation.Round, headerInformation.SenderPubkey.ToHex()); } if (headerInformation.Behaviour == AElfConsensusBehaviour.TinyBlock) { headerInformation.Round = currentRound.RecoverFromTinyBlock(headerInformation.Round, headerInformation.SenderPubkey.ToHex()); } var isContainPreviousInValue = !currentRound.IsMinerListJustChanged; if (headerInformation.Round.GetHash(isContainPreviousInValue) != currentRound.GetHash(isContainPreviousInValue)) { Context.LogDebug(() => $"Round information of block header:\n{headerInformation.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 }); }
private async Task <AElfConsensusTriggerInformation> GetConsensusTriggerInfoAsync( AEDPoSContractImplContainer.AEDPoSContractImplStub contractStub, BytesValue pubkey) { var command = await contractStub.GetConsensusCommand.CallAsync(pubkey); var hint = AElfConsensusHint.Parser.ParseFrom(command.Hint); var triggerInformation = new AElfConsensusTriggerInformation { Behaviour = hint.Behaviour, // It doesn't matter for testing. InValue = Hash.FromString($"InValueOf{pubkey}"), PreviousInValue = Hash.FromString($"InValueOf{pubkey}"), Pubkey = pubkey.Value }; var consensusExtraData = await contractStub.GetConsensusExtraData.CallAsync(new BytesValue { Value = triggerInformation.ToByteString() }); var consensusHeaderInformation = new AElfConsensusHeaderInformation(); consensusHeaderInformation.MergeFrom(consensusExtraData.Value); Debug.WriteLine($"Current header information: {consensusHeaderInformation}"); // Validate consensus extra data. { var validationResult = await _contractStubs.First().ValidateConsensusBeforeExecution.CallAsync(consensusExtraData); if (!validationResult.Success) { throw new Exception($"Consensus extra data validation failed: {validationResult.Message}"); } } return(triggerInformation); }
public override ValidationResult ValidateConsensusAfterExecution(BytesValue input1) { var input = new AElfConsensusHeaderInformation(); input.MergeFrom(input1.Value); if (TryToGetCurrentRoundInformation(out var currentRound)) { var isContainPreviousInValue = input.Behaviour != AElfConsensusBehaviour.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 }); }
/// <summary> /// This method will be executed before executing a block. /// </summary> /// <param name="extraData"></param> /// <returns></returns> private ValidationResult ValidateBeforeExecution(AElfConsensusHeaderInformation extraData) { // According to current round information: if (!TryToGetCurrentRoundInformation(out var baseRound)) { return(new ValidationResult { Success = false, Message = "Failed to get current round information." }); } // Skip the certain initial miner during first several rounds. (When other nodes haven't produce blocks yet.) if (baseRound.RealTimeMinersInformation.Count != 1 && Context.CurrentHeight < AEDPoSContractConstants.MaximumTinyBlocksCount.Mul(3)) { string producedMiner = null; var result = true; for (var i = baseRound.RoundNumber; i > 0; i--) { var producedMiners = State.Rounds[i].RealTimeMinersInformation.Values .Where(m => m.ActualMiningTimes.Any()).ToList(); if (producedMiners.Count != 1) { result = false; break; } if (producedMiner == null) { producedMiner = producedMiners.Single().Pubkey; } else if (producedMiner != producedMiners.Single().Pubkey) { result = false; } } if (result) { return(new ValidationResult { Success = true }); } } if (extraData.Behaviour == AElfConsensusBehaviour.UpdateValue) { baseRound.RecoverFromUpdateValue(extraData.Round, extraData.SenderPubkey.ToHex()); } if (extraData.Behaviour == AElfConsensusBehaviour.TinyBlock) { baseRound.RecoverFromTinyBlock(extraData.Round, extraData.SenderPubkey.ToHex()); } var validationContext = new ConsensusValidationContext { BaseRound = baseRound, CurrentTermNumber = State.CurrentTermNumber.Value, CurrentRoundNumber = State.CurrentRoundNumber.Value, PreviousRound = TryToGetPreviousRoundInformation(out var previousRound) ? previousRound : new Round(), LatestPubkeyToTinyBlocksCount = State.LatestPubkeyToTinyBlocksCount.Value, ExtraData = extraData }; /* Ask several questions: */ // Add basic providers at first. var validationProviders = new List <IHeaderInformationValidationProvider> { // Is sender in miner list (of base round)? new MiningPermissionValidationProvider(), // Is this block produced in proper time? new TimeSlotValidationProvider(), // Is sender produced too many blocks at one time? new ContinuousBlocksValidationProvider() }; switch (extraData.Behaviour) { case AElfConsensusBehaviour.UpdateValue: validationProviders.Add(new UpdateValueValidationProvider()); // Is confirmed lib height and lib round number went down? (Which should not happens.) validationProviders.Add(new LibInformationValidationProvider()); break; case AElfConsensusBehaviour.NextRound: // Is sender's order of next round correct? validationProviders.Add(new NextRoundMiningOrderValidationProvider()); validationProviders.Add(new RoundTerminateValidationProvider()); break; case AElfConsensusBehaviour.NextTerm: validationProviders.Add(new RoundTerminateValidationProvider()); break; } var service = new HeaderInformationValidationService(validationProviders); Context.LogDebug(() => $"Validating behaviour: {extraData.Behaviour.ToString()}"); var validationResult = service.ValidateInformation(validationContext); if (validationResult.Success == false) { Context.LogDebug(() => $"Consensus Validation before execution failed : {validationResult.Message}"); } return(validationResult); } }
/// <summary> /// This method will be executed before executing a block. /// </summary> /// <param name="extraData"></param> /// <returns></returns> private ValidationResult ValidateBeforeExecution(AElfConsensusHeaderInformation extraData) { // According to current round information: if (!TryToGetCurrentRoundInformation(out var baseRound)) { return(new ValidationResult { Success = false, Message = "Failed to get current round information." }); } if (extraData.Behaviour == AElfConsensusBehaviour.UpdateValue) { baseRound.RecoverFromUpdateValue(extraData.Round, extraData.SenderPubkey.ToHex()); } if (extraData.Behaviour == AElfConsensusBehaviour.TinyBlock) { baseRound.RecoverFromTinyBlock(extraData.Round, extraData.SenderPubkey.ToHex()); } var validationContext = new ConsensusValidationContext { BaseRound = baseRound, CurrentTermNumber = State.CurrentTermNumber.Value, CurrentRoundNumber = State.CurrentRoundNumber.Value, PreviousRound = TryToGetPreviousRoundInformation(out var previousRound) ? previousRound : new Round(), LatestPubkeyToTinyBlocksCount = State.LatestPubkeyToTinyBlocksCount.Value, ExtraData = extraData }; /* Ask several questions: */ // Add basic providers at first. var validationProviders = new List <IHeaderInformationValidationProvider> { // Is sender in miner list (of base round)? new MiningPermissionValidationProvider(), // Is this block produced in proper time? new TimeSlotValidationProvider(), // Is sender produced too many blocks at one time? new ContinuousBlocksValidationProvider() }; switch (extraData.Behaviour) { case AElfConsensusBehaviour.UpdateValue: validationProviders.Add(new UpdateValueValidationProvider()); // Is confirmed lib height and lib round number went down? (Which should not happens.) validationProviders.Add(new LibInformationValidationProvider()); break; case AElfConsensusBehaviour.NextRound: // Is sender's order of next round correct? validationProviders.Add(new NextRoundMiningOrderValidationProvider()); validationProviders.Add(new RoundTerminateValidationProvider()); break; case AElfConsensusBehaviour.NextTerm: validationProviders.Add(new RoundTerminateValidationProvider()); break; } var service = new HeaderInformationValidationService(validationProviders); Context.LogDebug(() => $"Validating behaviour: {extraData.Behaviour.ToString()}"); var validationResult = service.ValidateInformation(validationContext); if (validationResult.Success == false) { Context.LogDebug(() => $"Consensus Validation before execution failed : {validationResult.Message}"); } return(validationResult); } }
/// <summary> /// This method will be executed before executing a block. /// </summary> /// <param name="extraData"></param> /// <returns></returns> private ValidationResult ValidateBeforeExecution(AElfConsensusHeaderInformation extraData) { // We can trust this because we already validated the pubkey // during `AEDPoSExtraDataExtractor.ExtractConsensusExtraData` var pubkey = extraData.SenderPubkey.ToHex(); // This validation focuses on the new round information. var providedRound = extraData.Round; // According to current round information: if (!TryToGetCurrentRoundInformation(out var baseRound)) { return(new ValidationResult { Success = false, Message = "Failed to get current round information." }); } /* Ask several questions: */ // Is sender in miner list? if (!baseRound.IsInMinerList(pubkey)) { Context.LogDebug(() => "Sender is not a miner."); return(new ValidationResult { Success = false, Message = $"Sender {pubkey} is not a miner." }); } // If provided round is a new round if (providedRound.RoundId != baseRound.RoundId) { // Is round information fits time slot rule? var timeSlotsCheckResult = providedRound.CheckRoundTimeSlots(); if (!timeSlotsCheckResult.Success) { Context.LogDebug(() => $"Round time slots incorrect: {timeSlotsCheckResult.Message}"); return(timeSlotsCheckResult); } } else { // Is sender respect his time slot? // It is maybe failing due to using too much time producing previous tiny blocks. if (!CheckMinerTimeSlot(providedRound, pubkey)) { Context.LogDebug(() => "Time slot already passed before execution."); return(new ValidationResult { Message = "Time slot already passed before execution." }); } } // Is sender produce too many continuous blocks? // Skip first two rounds. if (providedRound.RoundNumber > 2 && baseRound.RealTimeMinersInformation.Count != 1) { var latestProviderToTinyBlocksCount = State.LatestProviderToTinyBlocksCount.Value; if (latestProviderToTinyBlocksCount != null && latestProviderToTinyBlocksCount.Pubkey == pubkey && latestProviderToTinyBlocksCount.BlocksCount < 0) { Context.LogDebug(() => $"Sender {pubkey} produced too many continuous blocks."); return(new ValidationResult { Message = "Sender produced too many continuous blocks." }); } } // Is sender's order of next round correct? // Miners that have determined the order of the next round should be equal to // miners that mined blocks during current round. if (providedRound.RealTimeMinersInformation.Values.Where(m => m.FinalOrderOfNextRound > 0).Distinct() .Count() != providedRound.RealTimeMinersInformation.Values.Count(m => m.OutValue != null)) { return(new ValidationResult { Message = "Invalid FinalOrderOfNextRound." }); } // Is confirmed lib height and lib round number went down? if (baseRound.ConfirmedIrreversibleBlockHeight > providedRound.ConfirmedIrreversibleBlockHeight || baseRound.ConfirmedIrreversibleBlockRoundNumber > providedRound.ConfirmedIrreversibleBlockRoundNumber) { return(new ValidationResult { Message = "Incorrect confirmed lib information." }); } switch (extraData.Behaviour) { case AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue: case AElfConsensusBehaviour.UpdateValue: return(ValidationForUpdateValue(extraData)); case AElfConsensusBehaviour.NextRound: return(ValidationForNextRound(extraData)); case AElfConsensusBehaviour.NextTerm: return(ValidationForNextTerm(extraData)); } return(new ValidationResult { Success = true }); }
public override TransactionList GenerateConsensusTransactions(BytesValue input) { var triggerInformation = new AElfConsensusTriggerInformation(); triggerInformation.MergeFrom(input.Value); // Some basic checks. Assert(triggerInformation.Pubkey.Any(), "Data to request consensus information should contain public key."); var publicKey = triggerInformation.Pubkey; var consensusInformation = new AElfConsensusHeaderInformation(); consensusInformation.MergeFrom(GetConsensusBlockExtraData(input, true).Value); var round = consensusInformation.Round; var behaviour = consensusInformation.Behaviour; switch (behaviour) { case AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue: case AElfConsensusBehaviour.UpdateValue: return(new TransactionList { Transactions = { GenerateTransaction(nameof(UpdateValue), round.ExtractInformationToUpdateConsensus(publicKey.ToHex())) } }); case AElfConsensusBehaviour.TinyBlock: var minerInRound = round.RealTimeMinersInformation[publicKey.ToHex()]; return(new TransactionList { Transactions = { GenerateTransaction(nameof(UpdateTinyBlockInformation), new TinyBlockInput { ActualMiningTime = minerInRound.ActualMiningTimes.Last(), ProducedBlocks = minerInRound.ProducedBlocks, RoundId = round.RoundId }) } }); case AElfConsensusBehaviour.NextRound: return(new TransactionList { Transactions = { GenerateTransaction(nameof(NextRound), round) } }); case AElfConsensusBehaviour.NextTerm: return(new TransactionList { Transactions = { GenerateTransaction(nameof(NextTerm), round) } }); default: throw new ArgumentOutOfRangeException(); } }
public async Task MineBlockAsync(List <Transaction> transactions = null, bool withException = false) { if (!_isSystemContractsDeployed) { return; } if (transactions != null) { await _testDataProvider.AddTransactionListAsync(transactions); } var currentBlockTime = _testDataProvider.GetBlockTime(); { { var currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty()); if (currentRound.RoundNumber == 0) { throw new InitializationFailedException("Can't find current round information."); } } } var maximumBlocksCount = (await _contractStubs.First().GetMaximumBlocksCount.CallAsync(new Empty())).Value; var(contractStub, pubkey) = GetProperContractStub(currentBlockTime, maximumBlocksCount); currentBlockTime = _testDataProvider.GetBlockTime(); { var currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty()); if (currentRound.RoundNumber == 0) { throw new InitializationFailedException("Can't find current round information."); } } var command = await contractStub.GetConsensusCommand.CallAsync(pubkey); var hint = AElfConsensusHint.Parser.ParseFrom(command.Hint); var triggerInformation = new AElfConsensusTriggerInformation { Behaviour = hint.Behaviour, // It doesn't matter for testing. InValue = Hash.FromString($"InValueOf{pubkey}"), PreviousInValue = Hash.FromString($"InValueOf{pubkey}"), Pubkey = pubkey.Value }; var consensusExtraData = await contractStub.GetConsensusExtraData.CallAsync(new BytesValue { Value = triggerInformation.ToByteString() }); var consensusHeaderInformation = new AElfConsensusHeaderInformation(); consensusHeaderInformation.MergeFrom(consensusExtraData.Value); Debug.WriteLine($"Current header information: {consensusHeaderInformation}"); // Validate consensus extra data. { var validationResult = await _contractStubs.First().ValidateConsensusBeforeExecution.CallAsync(consensusExtraData); if (!validationResult.Success) { throw new Exception($"Consensus extra data validation failed: {validationResult.Message}"); } } var consensusTransaction = await contractStub.GenerateConsensusTransactions.CallAsync(new BytesValue { Value = triggerInformation.ToByteString() }); await MineAsync(contractStub, consensusTransaction.Transactions.First(), withException); _currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty()); Debug.WriteLine($"Update current round information.{_currentRound}"); if (!_isSkipped) { if (_currentRound.RealTimeMinersInformation.Any(i => i.Value.MissedTimeSlots != 0)) { var previousRound = await _contractStubs.First().GetPreviousRoundInformation.CallAsync(new Empty()); throw new BlockMiningException( $"Someone missed time slot.\n{_currentRound}\n{previousRound}\nCurrent block time: {currentBlockTime}"); } } _testDataProvider.SetBlockTime( consensusTransaction.Transactions.First().MethodName == nameof(AEDPoSContractImplContainer.AEDPoSContractImplStub.NextTerm) ? currentBlockTime.AddMilliseconds(AEDPoSExtensionConstants.MiningInterval) : currentBlockTime.AddMilliseconds(AEDPoSExtensionConstants.ActualMiningInterval)); await _testDataProvider.ResetAsync(); _isSkipped = false; }