Exemplo n.º 1
0
        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();
            }
        }
Exemplo n.º 5
0
        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();
        }
Exemplo n.º 6
0
        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);
        }
Exemplo n.º 8
0
        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();
        }
Exemplo n.º 9
0
        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());
            }
        }
Exemplo n.º 10
0
        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
            });
        }