Пример #1
0
        public async Task <Hash> RequestRandomNumberWithCommitmentSchemeTest()
        {
            await BlockMiningService.MineBlockToNextRoundAsync();

            var dict = await DeployCommitmentSchemeContract();

            CommitmentSchemeStub =
                GetTester <CommitmentSchemeContractContainer.CommitmentSchemeContractStub>(dict.First().Value,
                                                                                           SampleECKeyPairs.KeyPairs[0]);

            var commitment = Hash.FromMessage(Secret);
            var requestTx  = CommitmentSchemeStub.RequestRandomNumber.GetTransaction(commitment);
            await BlockMiningService.MineBlockAsync(new List <Transaction> {
                requestTx
            });

            var requestTrace      = TransactionTraceProvider.GetTransactionTrace(requestTx.GetHash());
            var randomNumberOrder = new RandomNumberOrder();

            randomNumberOrder.MergeFrom(requestTrace.ReturnValue);
            randomNumberOrder.BlockHeight.ShouldBePositive();
            randomNumberOrder.TokenHash.ShouldBe(commitment);

            return(requestTx.GetHash());
        }
Пример #2
0
        public async Task OwnResourceTest()
        {
            await InitialTokenContract(false);

            // Check balance before mining
            {
                var cpuBalance = await GetCreatorBalanceOf("CPU");

                cpuBalance.ShouldBe(0);
                var ramBalance = await GetCreatorBalanceOf("RAM");

                ramBalance.ShouldBe(0);
                var diskBalance = await GetCreatorBalanceOf("DISK");

                diskBalance.ShouldBe(0);
                var netBalance = await GetCreatorBalanceOf("NET");

                netBalance.ShouldBe(0);
            }

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            var owningRental = await TokenStub.GetOwningRental.CallAsync(new Empty());

            owningRental.ResourceAmount["CPU"].ShouldBe(CpuAmount * Rental);
            owningRental.ResourceAmount["RAM"].ShouldBe(RamAmount * Rental);
            owningRental.ResourceAmount["DISK"].ShouldBe(DiskAmount * Rental);
            owningRental.ResourceAmount["NET"].ShouldBe(NetAmount * Rental);
        }
Пример #3
0
        public async Task RequestRandomNumberTest()
        {
            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            var requestTx      = ConsensusStub.RequestRandomNumber.GetTransaction(new Hash());
            var refBlockNumber = requestTx.RefBlockNumber;
            await BlockMiningService.MineBlockAsync(new List <Transaction>
            {
                requestTx
            });

            var requestTrace      = TransactionTraceProvider.GetTransactionTrace(requestTx.GetHash());
            var randomNumberOrder = new RandomNumberOrder();

            randomNumberOrder.MergeFrom(requestTrace.ReturnValue);
            var targetBlockNumber = randomNumberOrder.BlockHeight;

            targetBlockNumber.ShouldBeLessThan(refBlockNumber + 100);
        }
Пример #4
0
        private async Task InitialEconomicSystem()
        {
            // Profit distribution schemes related to Treasury must be created before initialization of Economic System.
            await BlockMiningService.MineBlockAsync(new List <Transaction>
            {
                TreasuryStub.InitialTreasuryContract.GetTransaction(new Empty()),
                TreasuryStub.InitialMiningRewardProfitItem.GetTransaction(new Empty())
            });

            await BlockMiningService.MineBlockAsync(new List <Transaction>
            {
                ElectionStub.InitialElectionContract.GetTransaction(new InitialElectionContractInput
                {
                    MinerList             = { MissionedECKeyPairs.InitialKeyPairs.Select(p => p.PublicKey.ToHex()) },
                    MinerIncreaseInterval = AEDPoSExtensionConstants.MinerIncreaseInterval,
                    TimeEachTerm          = AEDPoSExtensionConstants.TimeEachTerm,
                    MinimumLockTime       = EconomicTestConstants.MinimumLockTime,
                    MaximumLockTime       = EconomicTestConstants.MaximumLockTime
                }),
                ParliamentContractStub.Initialize.GetTransaction(new InitializeInput()),
                EconomicStub.InitialEconomicSystem.GetTransaction(new InitialEconomicSystemInput
                {
                    IsNativeTokenBurnable       = true,
                    MiningRewardTotalAmount     = 1_200_000_000_00000000,
                    NativeTokenDecimals         = 8,
                    NativeTokenSymbol           = EconomicTestConstants.TokenSymbol,
                    NativeTokenTotalSupply      = 10_000_000_000_00000000,
                    NativeTokenName             = "Native Token",
                    TransactionSizeFeeUnitPrice = 1000
                })
            });
Пример #5
0
 internal async Task ClaimProfits(IEnumerable <ECKeyPair> keyPairs, Hash schemeId)
 {
     var stubs = ConvertKeyPairsToProfitStubs(keyPairs);
     await BlockMiningService.MineBlockAsync(stubs.Select(s =>
                                                          s.ClaimProfits.GetTransaction(new ClaimProfitsInput
     {
         SchemeId = schemeId,
     })).ToList());
 }
Пример #6
0
 private async Task <Dictionary <Hash, Address> > DeployCommitmentSchemeContract()
 {
     return(await BlockMiningService.DeploySystemContractsAsync(new Dictionary <Hash, byte[]>
     {
         {
             CommitmentSchemeSmartContractAddressName,
             ContractsDeployer.GetContractCodes <AEDPoSExtensionDemoModule>().Last().Value
         }
     }, false));
 }
Пример #7
0
        public async Task RecordSideChainData_WithChainNotExist()
        {
            int parentChainId = 123;
            long lockedToken = 10;
            long parentChainHeightOfCreation = 10;
            var sideChainId1 =
                await InitAndCreateSideChainAsync(parentChainHeightOfCreation, parentChainId, lockedToken);

            // create second side chain
            long lockedTokenAmount = 10;
            await ApproveBalanceAsync(lockedTokenAmount);
            var sideChainCreationRequest = CreateSideChainCreationRequest(1, lockedTokenAmount, ByteString.Empty);

            var sideChainId2 = ChainHelper.GetChainId(2);

            await BlockMiningService.MineBlockAsync(new List<Transaction>
            {
                CrossChainContractStub.CreateSideChain.GetTransaction(sideChainCreationRequest)
            }, true);

            var fakeSideChainBlockHash = Hash.FromString("sideChainBlockHash");
            var fakeTxMerkleTreeRoot = Hash.FromString("txMerkleTreeRoot");
            var sideChainBlockData1 =
                CreateSideChainBlockData(fakeSideChainBlockHash, 1, sideChainId1, fakeTxMerkleTreeRoot);

            var sideChainBlockData2 =
                CreateSideChainBlockData(fakeSideChainBlockHash, 2, sideChainId2, fakeTxMerkleTreeRoot);
            int fakeChainId = 124;

            var sideChainBlockData3 =
                CreateSideChainBlockData(fakeSideChainBlockHash, 1, fakeChainId, fakeTxMerkleTreeRoot);
            var crossChainBlockData = new CrossChainBlockData
            {
                SideChainBlockData = {sideChainBlockData1, sideChainBlockData2, sideChainBlockData3}
            };

            await BlockMiningService.MineBlockAsync(new List<Transaction>
            {
                CrossChainContractStub.RecordCrossChainData.GetTransaction(crossChainBlockData)
            });

            var balance = await CrossChainContractStub.GetSideChainBalance.CallAsync(new SInt32Value {Value = sideChainId1});
            Assert.Equal(lockedToken - 1, balance.Value);

            var blockHeader = await BlockchainService.GetBestChainLastBlockHeaderAsync();
            var indexedCrossChainBlockData =
                await CrossChainContractStub.GetIndexedCrossChainBlockDataByHeight.CallAsync(new SInt64Value
                    {Value = blockHeader.Height});

            var expectedCrossChainBlocData = new CrossChainBlockData();
            expectedCrossChainBlocData.SideChainBlockData.Add(sideChainBlockData1);
            Assert.Equal(expectedCrossChainBlocData, indexedCrossChainBlockData);
        }
 protected async Task InitializeCrossChainContractAsync(long parentChainHeightOfCreation = 0,
                                                        int parentChainId = 0, bool withException = false)
 {
     await BlockMiningService.MineBlockAsync(new List <Transaction>
     {
         CrossChainContractStub.Initialize.GetTransaction(new InitializeInput
         {
             ParentChainId = parentChainId == 0 ? ChainHelper.ConvertBase58ToChainId("AELF") : parentChainId,
             CreationHeightOnParentChain = parentChainHeightOfCreation
         })
     }, withException);
 }
Пример #9
0
        public async Task CrossChain_Verification()
        {
            int parentChainId = 123;
            long lockedToken = 10;
            long parentChainHeightOfCreation = 10;
            var sideChainId =
                await InitAndCreateSideChainAsync(parentChainHeightOfCreation, parentChainId, lockedToken);
            var txId = Hash.FromString("sideChainBlockHash");
            
            var fakeHash1 = Hash.FromString("fake1");
            var fakeHash2 = Hash.FromString("fake2");

            var rawBytes = txId.ToByteArray()
                .Concat(EncodingHelper.GetBytesFromUtf8String(TransactionResultStatus.Mined.ToString()))
                .ToArray();
            var hash = Hash.FromRawBytes(rawBytes);

            var binaryMerkleTree = BinaryMerkleTree.FromLeafNodes(new[] {hash, fakeHash1, fakeHash2});
            var merkleTreeRoot = binaryMerkleTree.Root;
            var merklePath = binaryMerkleTree.GenerateMerklePath(0);
            Hash fakeTransactionStatusMerkleRoot = Hash.FromString("TransactionStatusMerkleRoot");
            var parentChainBlockData = CreateParentChainBlockData(parentChainHeightOfCreation, parentChainId,
                fakeTransactionStatusMerkleRoot);
            parentChainBlockData.CrossChainExtraData = new CrossChainExtraData
            {
                TransactionStatusMerkleTreeRoot = merkleTreeRoot
            };
            var crossChainBlockData = new CrossChainBlockData
            {
                ParentChainBlockData = {parentChainBlockData}
            };

            await BlockMiningService.MineBlockAsync(new List<Transaction>
            {
                CrossChainContractStub.RecordCrossChainData.GetTransaction(crossChainBlockData)
            });

            var verificationInput = new VerifyTransactionInput()
            {
                TransactionId = txId,
                ParentChainHeight = parentChainHeightOfCreation,
                Path = merklePath
            };

            var txRes = await CrossChainContractStub.VerifyTransaction.SendAsync(verificationInput);
            var verified = BoolValue.Parser.ParseFrom(txRes.TransactionResult.ReturnValue).Value;
            Assert.True(verified);
        }
Пример #10
0
        internal async Task <long> MineBlocksToNextTermAsync(long currentTermNumber = 0)
        {
            currentTermNumber = currentTermNumber == 0
                ? (await ConsensusStub.GetCurrentTermNumber.CallAsync(new Empty())).Value
                : currentTermNumber;
            var targetTermNumber = currentTermNumber + 1;
            var actualTermNumber = 0L;

            while (actualTermNumber != targetTermNumber)
            {
                await BlockMiningService.MineBlockAsync();

                actualTermNumber = (await ConsensusStub.GetCurrentTermNumber.CallAsync(new Empty())).Value;
            }

            return((await ConsensusStub.GetMinedBlocksOfPreviousTerm.CallAsync(new Empty())).Value);
        }
Пример #11
0
        public async Task PayDebtTest_NotEnough()
        {
            await OwnResourceTest();

            // Charge
            foreach (var symbol in Symbols)
            {
                await TokenStub.Issue.SendAsync(new IssueInput
                {
                    Symbol = symbol,
                    To     = Creator,
                    Amount = 1
                });
            }

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            var owningRental = await TokenStub.GetOwningRental.CallAsync(new Empty());

            owningRental.ResourceAmount["CPU"].ShouldBe(CpuAmount * Rental * 2 - 1);
            owningRental.ResourceAmount["RAM"].ShouldBe(RamAmount * Rental * 2 - 1);
            owningRental.ResourceAmount["DISK"].ShouldBe(DiskAmount * Rental * 2 - 1);
            owningRental.ResourceAmount["NET"].ShouldBe(NetAmount * Rental * 2 - 1);

            // Check balance before mining
            {
                var cpuBalance = await GetCreatorBalanceOf("CPU");

                cpuBalance.ShouldBe(0);
                var ramBalance = await GetCreatorBalanceOf("RAM");

                ramBalance.ShouldBe(0);
                var diskBalance = await GetCreatorBalanceOf("DISK");

                diskBalance.ShouldBe(0);
                var netBalance = await GetCreatorBalanceOf("NET");

                diskBalance.ShouldBe(0);
            }
        }
Пример #12
0
        public async Task ChargeRentalTest()
        {
            await InitialTokenContract();

            // Check balance before mining
            {
                var cpuBalance = await GetCreatorBalanceOf("CPU");

                cpuBalance.ShouldBe(ResourceSupply);
                var ramBalance = await GetCreatorBalanceOf("RAM");

                ramBalance.ShouldBe(ResourceSupply);
                var diskBalance = await GetCreatorBalanceOf("DISK");

                diskBalance.ShouldBe(ResourceSupply);
                var netBalance = await GetCreatorBalanceOf("NET");

                netBalance.ShouldBe(ResourceSupply);
            }

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            await BlockMiningService.MineBlockToNextRoundAsync();

            // Check balance before mining
            {
                var cpuBalance = await GetCreatorBalanceOf("CPU");

                cpuBalance.ShouldBe(ResourceSupply - CpuAmount * Rental);
                var ramBalance = await GetCreatorBalanceOf("RAM");

                ramBalance.ShouldBe(ResourceSupply - RamAmount * Rental);
                var diskBalance = await GetCreatorBalanceOf("DISK");

                diskBalance.ShouldBe(ResourceSupply - DiskAmount * Rental);
                var netBalance = await GetCreatorBalanceOf("NET");

                netBalance.ShouldBe(ResourceSupply - NetAmount * Rental);
            }
        }
Пример #13
0
        public async Task CrossChain_MerklePath()
        {
            int parentChainId = 123;
            long lockedToken = 10;
            long parentChainHeightOfCreation = 10;
            var sideChainId =
                await InitAndCreateSideChainAsync(parentChainHeightOfCreation, parentChainId, lockedToken);
            var transactionId = Hash.FromString("sideChainBlockHash");
            
            var fakeHash1 = Hash.FromString("fake1");
            var fakeHash2 = Hash.FromString("fake2");

            var binaryMerkleTree = BinaryMerkleTree.FromLeafNodes(new[] {transactionId, fakeHash1, fakeHash2});
            var merkleTreeRoot = binaryMerkleTree.Root;
            var merklePath = binaryMerkleTree.GenerateMerklePath(0);
            Hash fakeTransactionStatusMerkleRoot = Hash.FromString("TransactionStatusMerkleRoot");
            var parentChainBlockData = CreateParentChainBlockData(parentChainHeightOfCreation, parentChainId,
                fakeTransactionStatusMerkleRoot);

            long sideChainHeight = 1;
            parentChainBlockData.IndexedMerklePath.Add(sideChainHeight, merklePath);
            var crossChainBlockData = new CrossChainBlockData
            {
                ParentChainBlockData = {parentChainBlockData}
            };

            await BlockMiningService.MineBlockAsync(new List<Transaction>
            {
                CrossChainContractStub.RecordCrossChainData.GetTransaction(crossChainBlockData)
            });

            var crossChainMerkleProofContext =
                await CrossChainContractStub.GetBoundParentChainHeightAndMerklePathByHeight.CallAsync(new SInt64Value
                    {Value = sideChainHeight});
            Assert.Equal(merklePath.ToByteString(),
                crossChainMerkleProofContext.MerklePathFromParentChain.ToByteString());
            var calculatedRoot = crossChainMerkleProofContext.MerklePathFromParentChain
                .ComputeRootWithLeafNode(transactionId);
            Assert.Equal(merkleTreeRoot, calculatedRoot);
        }
Пример #14
0
        public async Task GetRandomNumberWithCommitmentSchemeTest()
        {
            var txHash = await RequestRandomNumberWithCommitmentSchemeTest();

            var requestTrace      = TransactionTraceProvider.GetTransactionTrace(txHash);
            var randomNumberOrder = new RandomNumberOrder();

            randomNumberOrder.MergeFrom(requestTrace.ReturnValue);
            await BlockMiningService.MineBlockAsync(randomNumberOrder.BlockHeight);

            var getTx = CommitmentSchemeStub.GetRandomNumber.GetTransaction(Secret);
            await BlockMiningService.MineBlockAsync(new List <Transaction>
            {
                getTx
            });

            var getTrace     = TransactionTraceProvider.GetTransactionTrace(getTx.GetHash());
            var randomNumber = new Hash();

            randomNumber.MergeFrom(getTrace.ReturnValue);
            randomNumber.Value.ShouldNotBeEmpty();
        }
        internal async Task ParliamentReachAnAgreementAsync(CreateProposalInput createProposalInput)
        {
            var createProposalTx = ParliamentStubs.First().CreateProposal.GetTransaction(createProposalInput);
            await BlockMiningService.MineBlockAsync(new List <Transaction>
            {
                createProposalTx
            });

            var proposalId = new Hash();

            proposalId.MergeFrom(TransactionTraceProvider.GetTransactionTrace(createProposalTx.GetHash()).ReturnValue);
            var approvals = new List <Transaction>();

            foreach (var stub in ParliamentStubs)
            {
                approvals.Add(stub.Approve.GetTransaction(proposalId));
            }

            await BlockMiningService.MineBlockAsync(approvals);

            await ParliamentStubs.First().Release.SendAsync(proposalId);
        }
Пример #16
0
        public async Task Demo_Test()
        {
            // Check round information after initialization.
            {
                var round = await ConsensusStub.GetCurrentRoundInformation.CallAsync(new Empty());

                round.RoundNumber.ShouldBe(1);
                round.TermNumber.ShouldBe(1);
                round.RealTimeMinersInformation.Count.ShouldBe(AEDPoSExtensionConstants.InitialKeyPairCount);

                TestDataProvider.SetBlockTime(
                    round.RealTimeMinersInformation.Single(m => m.Value.Order == 1).Value.ExpectedMiningTime +
                    new Duration {
                    Seconds = 1
                });
                var firstMinerPubkey   = round.RealTimeMinersInformation.Single(m => m.Value.Order == 1).Key;
                var currentMinerPubkey = await ConsensusStub.GetCurrentMinerPubkey.CallAsync(new Empty());

                currentMinerPubkey.Value.ShouldBe(firstMinerPubkey);
                (await ConsensusStub.IsCurrentMiner.CallAsync(
                     Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(firstMinerPubkey)))).Value
                .ShouldBeTrue();
            }

            // We can use this method process testing.
            // Basically this will produce one block with no transaction.
            await BlockMiningService.MineBlockAsync();

            // And this will produce one block with one transaction.
            // This transaction will call Create method of Token Contract.
            var createTokenTransaction = TokenStub.Create.GetTransaction(new CreateInput
            {
                Symbol      = "ELF",
                Decimals    = 8,
                TokenName   = "Test",
                Issuer      = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[0].PublicKey),
                IsBurnable  = true,
                TotalSupply = 1_000_000_000_00000000
            });
        public async Task SetMaximumMinersCountTest(int targetMinersCount)
        {
            await BlockMiningService.MineBlockToNextTermAsync();

            InitialAcs3Stubs();
            await ParliamentStubs.First().Initialize.SendAsync(new Parliament.InitializeInput());

            var defaultOrganizationAddress =
                await ParliamentStubs.First().GetDefaultOrganizationAddress.CallAsync(new Empty());

            await ParliamentReachAnAgreementAsync(new CreateProposalInput
            {
                ToAddress          = ContractAddresses[ConsensusSmartContractAddressNameProvider.Name],
                ContractMethodName = nameof(ConsensusStub.SetMaximumMinersCount),
                Params             = new Int32Value
                {
                    Value = targetMinersCount
                }.ToByteString(),
                ExpiredTime         = TimestampHelper.GetUtcNow().AddDays(1),
                OrganizationAddress = defaultOrganizationAddress
            });

            {
                var currentMinersCount = (await ConsensusStub.GetCurrentMinerList.CallAsync(new Empty())).Pubkeys.Count;
                currentMinersCount.ShouldBe(5);
                var currentTermNumber = await BlockMiningService.MineBlockToNextTermAsync();

                currentTermNumber.ShouldBe(3);
            }

            {
                var currentMinersCount = (await ConsensusStub.GetCurrentMinerList.CallAsync(new Empty())).Pubkeys.Count;
                currentMinersCount.ShouldBe(Math.Min(targetMinersCount, 5));
                var currentTermNumber = await BlockMiningService.MineBlockToNextTermAsync();

                currentTermNumber.ShouldBe(4);
            }
        }
        public async Task <long> TreasuryDistribution_FirstTerm_Test()
        {
            const long period = 1;
            long       distributedAmount;

            // First 7 core data centers announce election.
            var announceTransactions = new List <Transaction>();

            ConvertKeyPairsToElectionStubs(
                MissionedECKeyPairs.CoreDataCenterKeyPairs.Take(7)).ForEach(stub =>
                                                                            announceTransactions.Add(stub.AnnounceElection.GetTransaction(new Empty())));
            await BlockMiningService.MineBlockAsync(announceTransactions);

            // Check candidates.
            var candidates = await ElectionStub.GetCandidates.CallAsync(new Empty());

            candidates.Value.Count.ShouldBe(7);

            // First 10 citizens do some votes.
            var votesTransactions = new List <Transaction>();

            candidates.Value.ToList().ForEach(c =>
                                              votesTransactions.AddRange(GetVoteTransactions(5, 100, c.ToHex(), 10)));
            await BlockMiningService.MineBlockAsync(votesTransactions);

            // Check voted candidates
            var votedCandidates = await ElectionStub.GetVotedCandidates.CallAsync(new Empty());

            votedCandidates.Value.Count.ShouldBe(7);

            var minedBlocksInFirstRound = await MineBlocksToNextTermAsync(1);

            // Check new term.
            {
                var round = await ConsensusStub.GetCurrentRoundInformation.CallAsync(new Empty());

                round.TermNumber.ShouldBe(2);

                // Now we have 12 miners.
                var currentMiners = await ConsensusStub.GetCurrentMinerList.CallAsync(new Empty());

                currentMiners.Pubkeys.Count.ShouldBe(12);
                // And none of the initial miners was replaced.
                MissionedECKeyPairs.InitialKeyPairs.Select(p => p.PublicKey.ToHex())
                .Except(currentMiners.Pubkeys.Select(p => p.ToHex())).Count().ShouldBe(0);
            }

            // Check distributed total amount.
            {
                distributedAmount = minedBlocksInFirstRound * EconomicTestConstants.RewardPerBlock;
                var distributedInformation = await ProfitStub.GetDistributedProfitsInfo.CallAsync(new SchemePeriod
                {
                    SchemeId = _treasurySchemeId,
                    Period   = period
                });

                distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol].ShouldBe(distributedAmount);
            }

            // Check amount distributed to each scheme.
            {
                // Miner Basic Reward: 40%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.MinerBasicReward].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount * 2 / 5);
                }

                // Backup Subsidy: 20%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.BackupSubsidy].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount / 5);
                }

                // Citizen Welfare: -20% (Burned)
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.CitizenWelfare].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(-distributedAmount / 5);
                }

                // Votes Weight Reward: -10% (Burned)
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.VotesWeightReward].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(-distributedAmount / 10);
                }

                // Re-Election Reward: -10% (Burned)
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.ReElectionReward].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(-distributedAmount / 10);
                }
                return(distributedAmount);
            }
        }
        public async Task <TreasuryDistributionInformation> TreasuryDistribution_ThirdTerm_Test()
        {
            var        information = new TreasuryDistributionInformation();
            const long period      = 3;
            long       distributedAmount;

            var termNumber = (await ConsensusStub.GetCurrentTermNumber.CallAsync(new Empty())).Value;

            if (termNumber < 3)
            {
                await TreasuryDistribution_SecondTerm_Test();
            }

            // 10 validation data centers announce election.
            var announceTransactions = new List <Transaction>();

            ConvertKeyPairsToElectionStubs(
                MissionedECKeyPairs.ValidationDataCenterKeyPairs.Take(10)).ForEach(stub =>
                                                                                   announceTransactions.Add(stub.AnnounceElection.GetTransaction(new Empty())));
            await BlockMiningService.MineBlockAsync(announceTransactions);

            // Check candidates.
            var candidates = await ElectionStub.GetCandidates.CallAsync(new Empty());

            candidates.Value.Count.ShouldBe(27);

            // First 10 citizens do some votes.
            var votesTransactions = new List <Transaction>();

            candidates.Value.ToList().ForEach(c =>
                                              votesTransactions.AddRange(GetVoteTransactions(5, 100, c.ToHex(), 20)));
            await BlockMiningService.MineBlockAsync(votesTransactions);

            // Check voted candidates
            var votedCandidates = await ElectionStub.GetVotedCandidates.CallAsync(new Empty());

            votedCandidates.Value.Count.ShouldBe(27);

            var minedBlocksInFirstRound = await MineBlocksToNextTermAsync(3);

            // Check term number.
            {
                var round = await ConsensusStub.GetCurrentRoundInformation.CallAsync(new Empty());

                round.TermNumber.ShouldBe(4);
            }

            // Check distributed total amount.
            {
                distributedAmount = minedBlocksInFirstRound * EconomicTestConstants.RewardPerBlock;
                var distributedInformation = await ProfitStub.GetDistributedProfitsInfo.CallAsync(new SchemePeriod
                {
                    SchemeId = _treasurySchemeId,
                    Period   = period
                });

                distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol].ShouldBe(distributedAmount);

                information.TotalAmount = distributedAmount;
            }

            // Check amount distributed to each scheme.
            {
                // Miner Basic Reward: 40%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.MinerBasicReward].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount * 2 / 5);
                    var totalShares             = distributedInformation.TotalShares;
                    var previousTermInformation =
                        ConsensusStub.GetPreviousTermInformation.CallAsync(new SInt64Value {
                        Value = 3
                    }).Result;
                    totalShares.ShouldBe(
                        previousTermInformation.RealTimeMinersInformation.Values.Sum(i => i.ProducedBlocks));

                    information[SchemeType.MinerBasicReward] = new DistributionInformation
                    {
                        Amount      = amount,
                        TotalShares = totalShares
                    };
                }

                // Backup Subsidy: 20%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.BackupSubsidy].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount / 5);
                    var totalShares = distributedInformation.TotalShares;
                    totalShares.ShouldBe(27);

                    information[SchemeType.BackupSubsidy] = new DistributionInformation
                    {
                        Amount      = amount,
                        TotalShares = totalShares
                    };
                }

                // Citizen Welfare: 20%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.CitizenWelfare].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount / 5);
                    var totalShares = distributedInformation.TotalShares;
                    totalShares.ShouldBePositive();

                    information[SchemeType.CitizenWelfare] = new DistributionInformation
                    {
                        Amount      = amount,
                        TotalShares = totalShares
                    };
                }

                // Votes Weight Reward: 10%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.VotesWeightReward].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount / 10);
                    var totalShares = distributedInformation.TotalShares;
                    totalShares.ShouldBe(7000 + 17000);

                    information[SchemeType.VotesWeightReward] = new DistributionInformation
                    {
                        Amount      = amount,
                        TotalShares = totalShares
                    };
                }

                // Re-Election Reward: 10%
                {
                    var distributedInformation =
                        await GetDistributedInformationAsync(_schemes[SchemeType.ReElectionReward].SchemeId, period);

                    var amount = distributedInformation.ProfitsAmount[EconomicTestConstants.TokenSymbol];
                    amount.ShouldBe(distributedAmount / 10);
                    var totalShares = distributedInformation.TotalShares;
                    totalShares.ShouldBe(7);

                    information[SchemeType.ReElectionReward] = new DistributionInformation
                    {
                        Amount      = amount,
                        TotalShares = totalShares
                    };
                }
            }

            return(information);
        }