internal async Task <Dictionary <string, DPoSTriggerInformation> > GenerateEncryptedMessagesTest()
        {
            var firstRound = await BootMiner.GetCurrentRoundInformation.CallAsync(new Empty());

            var randomHashes = Enumerable.Range(0, MinersCount).Select(_ => Hash.Generate()).ToList();
            var triggers     = Enumerable.Range(0, MinersCount).Select(i => new DPoSTriggerInformation
            {
                PublicKey  = ByteString.CopyFrom(InitialMinersKeyPairs[i].PublicKey),
                RandomHash = randomHashes[i]
            }).ToDictionary(t => t.PublicKey.ToHex(), t => t);

            foreach (var minerInRound in firstRound.RealTimeMinersInformation.Values.OrderBy(m => m.Order))
            {
                var currentKeyPair = InitialMinersKeyPairs.First(p => p.PublicKey.ToHex() == minerInRound.PublicKey);

                ECKeyPairProvider.SetECKeyPair(currentKeyPair);

                BlockTimeProvider.SetBlockTime(minerInRound.ExpectedMiningTime.ToDateTime());

                var tester            = GetConsensusContractTester(currentKeyPair);
                var headerInformation =
                    await tester.GetInformationToUpdateConsensus.CallAsync(triggers[minerInRound.PublicKey]);

                var encryptedInValues = headerInformation.Round.RealTimeMinersInformation[minerInRound.PublicKey]
                                        .EncryptedInValues;

                encryptedInValues.Count.ShouldBe(MinersCount - 1);
                foreach (var(key, value) in encryptedInValues)
                {
                    InitialMinersKeyPairs.Select(p => p.PublicKey.ToHex()).ShouldContain(key);
                    value.ShouldNotBeEmpty();
                }

                // Update consensus information.
                var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.PublicKey);
                await tester.UpdateValue.SendAsync(toUpdate);
            }

            var updatedRound = await BootMiner.GetCurrentRoundInformation.CallAsync(new Empty());

            foreach (var minerInRound in updatedRound.RealTimeMinersInformation.Values)
            {
                minerInRound.EncryptedInValues.Count.ShouldBe(MinersCount - 1);
            }

            return(triggers);
        }
        public void OffChainDecryptMessageTest()
        {
            var message         = Hash.Generate().ToHex();
            var secrets         = SecretSharingHelper.EncodeSecret(message, MinimumCount, MinersCount);
            var encryptedValues = new Dictionary <string, byte[]>();
            var decryptedValues = new Dictionary <string, byte[]>();
            var ownerKeyPair    = InitialMinersKeyPairs[0];
            var othersKeyPairs  = InitialMinersKeyPairs.Skip(1).ToList();
            var decryptResult   = "";

            var initial = 0;

            foreach (var keyPair in othersKeyPairs)
            {
                var encryptedMessage = CryptoHelpers.EncryptMessage(ownerKeyPair.PrivateKey, keyPair.PublicKey,
                                                                    Encoding.UTF8.GetBytes(secrets[initial++]));
                encryptedValues.Add(keyPair.PublicKey.ToHex(), encryptedMessage);
            }

            // Check encrypted values.
            encryptedValues.Count.ShouldBe(MinersCount - 1);

            // Others try to recover.
            foreach (var keyPair in othersKeyPairs)
            {
                var cipherMessage  = encryptedValues[keyPair.PublicKey.ToHex()];
                var decryptMessage =
                    CryptoHelpers.DecryptMessage(ownerKeyPair.PublicKey, keyPair.PrivateKey, cipherMessage);
                decryptedValues.Add(keyPair.PublicKey.ToHex(), decryptMessage);

                if (decryptedValues.Count >= MinimumCount)
                {
                    decryptResult = SecretSharingHelper.DecodeSecret(
                        decryptedValues.Values.Select(v => Encoding.UTF8.GetString(v)).ToList(),
                        Enumerable.Range(1, MinimumCount).ToList(), MinimumCount);
                    break;
                }
            }

            decryptResult.ShouldBe(message);
        }
        public async Task DecryptMessageTest()
        {
            var previousTriggers = await GenerateEncryptedMessagesTest();

            await BootMinerChangeRoundAsync();

            var currentRound = await BootMiner.GetCurrentRoundInformation.CallAsync(new Empty());

            var randomHashes = Enumerable.Range(0, MinersCount).Select(_ => Hash.Generate()).ToList();
            var triggers     = Enumerable.Range(0, MinersCount).Select(i => new DPoSTriggerInformation
            {
                PublicKey          = ByteString.CopyFrom(InitialMinersKeyPairs[i].PublicKey),
                RandomHash         = randomHashes[i],
                PreviousRandomHash = previousTriggers[InitialMinersKeyPairs[i].PublicKey.ToHex()].RandomHash
            }).ToDictionary(t => t.PublicKey.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 = InitialMinersKeyPairs.First(p => p.PublicKey.ToHex() == minerInRound.PublicKey);

                ECKeyPairProvider.SetECKeyPair(currentKeyPair);

                BlockTimeProvider.SetBlockTime(minerInRound.ExpectedMiningTime.ToDateTime());

                var tester            = GetConsensusContractTester(currentKeyPair);
                var headerInformation =
                    await tester.GetInformationToUpdateConsensus.CallAsync(triggers[minerInRound.PublicKey]);

                // Update consensus information.
                var toUpdate = headerInformation.Round.ExtractInformationToUpdateConsensus(minerInRound.PublicKey);
                await tester.UpdateValue.SendAsync(toUpdate);
            }

            // But in values all filled.
            var secondRound = await BootMiner.GetCurrentRoundInformation.CallAsync(new Empty());

            secondRound.RealTimeMinersInformation.Values.Count(v => v.PreviousInValue != null).ShouldBe(MinersCount);
        }
        public async Task Get_Organization_Test()
        {
            await InitializeParliamentContracts();

            var minimalApprovalThreshold   = 10000 / MinersCount;
            var maximalAbstentionThreshold = 2000 / MinersCount;
            var maximalRejectionThreshold  = 3000 / MinersCount;
            var minimalVoteThreshold       = 11000 / MinersCount;

            var createOrganizationInput = new CreateOrganizationInput
            {
                ProposalReleaseThreshold = new ProposalReleaseThreshold
                {
                    MinimalApprovalThreshold   = minimalApprovalThreshold,
                    MaximalAbstentionThreshold = maximalAbstentionThreshold,
                    MaximalRejectionThreshold  = maximalRejectionThreshold,
                    MinimalVoteThreshold       = minimalVoteThreshold
                }
            };
            var minerParliamentContractStub = GetParliamentContractTester(InitialMinersKeyPairs.First());
            var transactionResult           =
                await minerParliamentContractStub.CreateOrganization.SendAsync(createOrganizationInput);

            var organizationCalculated = ParliamentContractStub.CalculateOrganizationAddress
                                         .CallAsync(createOrganizationInput).Result;
            var organizationAddress = transactionResult.Output;

            organizationCalculated.ShouldBe(organizationAddress);
            var getOrganization = await ParliamentContractStub.GetOrganization.CallAsync(organizationAddress);

            getOrganization.OrganizationAddress.ShouldBe(organizationAddress);
            getOrganization.ProposalReleaseThreshold.MinimalApprovalThreshold.ShouldBe(minimalApprovalThreshold);
            getOrganization.ProposalReleaseThreshold.MinimalVoteThreshold.ShouldBe(minimalVoteThreshold);
            getOrganization.ProposalReleaseThreshold.MaximalAbstentionThreshold.ShouldBe(maximalAbstentionThreshold);
            getOrganization.ProposalReleaseThreshold.MaximalRejectionThreshold.ShouldBe(maximalRejectionThreshold);
            getOrganization.OrganizationHash.ShouldBe(Hash.FromMessage(createOrganizationInput));
        }
        public async Task Normal_Round_First_Miner_Test()
        {
            await BootMinerChangeRoundAsync();

            // Check second round information.
            var secondRound = await BootMiner.GetCurrentRoundInformation.CallAsync(new Empty());

            secondRound.RoundNumber.ShouldBe(2);

            var firstMinerInSecondRound =
                secondRound.RealTimeMinersInformation.Values.First(m => m.Order == 1).PublicKey;

            var secondRoundStartTime =
                BlockchainStartTime.GetRoundExpectedStartTime(secondRound.TotalMilliseconds(MiningInterval), 2);

            var minerKeyPair = InitialMinersKeyPairs.First(k => k.PublicKey.ToHex() == firstMinerInSecondRound);
            var miner        = GetConsensusContractTester(minerKeyPair);

            var expectedMiningTime = secondRound.RealTimeMinersInformation[minerKeyPair.PublicKey.ToHex()]
                                     .ExpectedMiningTime.ToDateTime();

            // Normal block
            {
                // Set current time as the start time of 2rd round.
                BlockTimeProvider.SetBlockTime(secondRoundStartTime);


                var leftMilliseconds = (int)(expectedMiningTime - secondRoundStartTime).TotalMilliseconds;

                var command = await miner.GetConsensusCommand.CallAsync(new CommandInput
                                                                        { PublicKey = ByteString.CopyFrom(minerKeyPair.PublicKey) });

                command.NextBlockMiningLeftMilliseconds.ShouldBe(leftMilliseconds);
                command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval);
                command.Hint.ShouldBe(new DPoSHint {
                    Behaviour = DPoSBehaviour.UpdateValue
                }
                                      .ToByteArray());
            }

            // Extra block
            {
                // Pretend the miner passed his time slot.
                var fakeTime = expectedMiningTime.AddMilliseconds(MiningInterval);
                BlockTimeProvider.SetBlockTime(fakeTime);

                var extraBlockMiningTime = secondRound.GetExpectedEndTime().ToDateTime().AddMilliseconds(MiningInterval);
                var leftMilliseconds     = (int)(extraBlockMiningTime - fakeTime).TotalMilliseconds;

                var command = await miner.GetConsensusCommand.CallAsync(new CommandInput
                                                                        { PublicKey = ByteString.CopyFrom(minerKeyPair.PublicKey) });

                if (secondRound.GetExtraBlockProducerInformation().PublicKey == minerKeyPair.PublicKey.ToHex())
                {
                    // If this node is EBP
                    command.NextBlockMiningLeftMilliseconds.ShouldBe(
                        (int)(secondRound.GetExtraBlockMiningTime() - fakeTime).TotalMilliseconds);
                }
                else
                {
                    command.NextBlockMiningLeftMilliseconds.ShouldBe(leftMilliseconds);
                }
                command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval);
                command.Hint.ShouldBe(new DPoSHint {
                    Behaviour = DPoSBehaviour.NextRound
                }
                                      .ToByteArray());
            }
        }