diff --git a/protobuf/profit_contract.proto b/protobuf/profit_contract.proto index 12fb4bef47..445b981142 100644 --- a/protobuf/profit_contract.proto +++ b/protobuf/profit_contract.proto @@ -120,6 +120,7 @@ message ReleaseProfitInput { Hash profit_id = 1; sint64 period = 2; sint64 amount = 3; + sint64 total_weight = 4; } message ProfitDetails { diff --git a/src/AElf.Contracts.Consensus.AEDPoS/AElfConsensusContract.cs b/src/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs similarity index 99% rename from src/AElf.Contracts.Consensus.AEDPoS/AElfConsensusContract.cs rename to src/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs index 0a9fb5f5d3..90d3a29a0c 100644 --- a/src/AElf.Contracts.Consensus.AEDPoS/AElfConsensusContract.cs +++ b/src/AElf.Contracts.Consensus.AEDPoS/AEDPoSContract.cs @@ -212,7 +212,7 @@ private void TryToFindLastIrreversibleBlock() Context.LogDebug(() => $"LIB found, offset is {offset}"); Context.Fire(new IrreversibleBlockFound() { - Offset = offset.Mul(AElfConsensusContractConstants.TinyBlocksNumber) + Offset = offset.Mul(AEDPoSContractConstants.TinyBlocksNumber) }); } } diff --git a/src/AElf.Contracts.Consensus.AEDPoS/AElfConsensusContractConstants.cs b/src/AElf.Contracts.Consensus.AEDPoS/AEDPoSContractConstants.cs similarity index 65% rename from src/AElf.Contracts.Consensus.AEDPoS/AElfConsensusContractConstants.cs rename to src/AElf.Contracts.Consensus.AEDPoS/AEDPoSContractConstants.cs index a6164599a9..b882e0c3cd 100644 --- a/src/AElf.Contracts.Consensus.AEDPoS/AElfConsensusContractConstants.cs +++ b/src/AElf.Contracts.Consensus.AEDPoS/AEDPoSContractConstants.cs @@ -1,6 +1,6 @@ namespace AElf.Contracts.Consensus.AEDPoS { - public static class AElfConsensusContractConstants + public static class AEDPoSContractConstants { public const int TinyBlocksNumber = 8; } diff --git a/src/AElf.Contracts.Consensus.AEDPoS/HelpMethods.cs b/src/AElf.Contracts.Consensus.AEDPoS/HelpMethods.cs index 7e9a7f4042..438c3fafe1 100644 --- a/src/AElf.Contracts.Consensus.AEDPoS/HelpMethods.cs +++ b/src/AElf.Contracts.Consensus.AEDPoS/HelpMethods.cs @@ -50,7 +50,7 @@ private AElfConsensusBehaviour GetBehaviour(string publicKey, DateTime dateTime, if (currentRound.ExtraBlockProducerOfPreviousRound == publicKey && dateTime < currentRound.GetStartTime() && - minerInRound.ProducedTinyBlocks < AElfConsensusContractConstants.TinyBlocksNumber) + minerInRound.ProducedTinyBlocks < AEDPoSContractConstants.TinyBlocksNumber) { return AElfConsensusBehaviour.TinyBlock; } @@ -61,12 +61,12 @@ private AElfConsensusBehaviour GetBehaviour(string publicKey, DateTime dateTime, return AElfConsensusBehaviour.UpdateValue; } } - else if (minerInRound.ProducedTinyBlocks < AElfConsensusContractConstants.TinyBlocksNumber) + else if (minerInRound.ProducedTinyBlocks < AEDPoSContractConstants.TinyBlocksNumber) { return AElfConsensusBehaviour.TinyBlock; } else if (currentRound.ExtraBlockProducerOfPreviousRound == publicKey && - minerInRound.ProducedTinyBlocks < AElfConsensusContractConstants.TinyBlocksNumber.Mul(2)) + minerInRound.ProducedTinyBlocks < AEDPoSContractConstants.TinyBlocksNumber.Mul(2)) { return AElfConsensusBehaviour.TinyBlock; } @@ -143,22 +143,22 @@ private ConsensusCommand GetConsensusCommand(AElfConsensusBehaviour behaviour, R if (currentRound.ExtraBlockProducerOfPreviousRound != publicKey) { expectedMiningTime = expectedMiningTime.ToDateTime().AddMilliseconds(producedTinyBlocks - .Mul(miningInterval).Div(AElfConsensusContractConstants.TinyBlocksNumber)) + .Mul(miningInterval).Div(AEDPoSContractConstants.TinyBlocksNumber)) .ToTimestamp(); } else { // EBP of previous round will produce double tiny blocks. This is for normal time slot of current round. expectedMiningTime = expectedMiningTime.ToDateTime().AddMilliseconds(producedTinyBlocks - .Sub(AElfConsensusContractConstants.TinyBlocksNumber) - .Mul(miningInterval).Div(AElfConsensusContractConstants.TinyBlocksNumber)).ToTimestamp(); + .Sub(AEDPoSContractConstants.TinyBlocksNumber) + .Mul(miningInterval).Div(AEDPoSContractConstants.TinyBlocksNumber)).ToTimestamp(); } } else if (previousRound != null) { // EBP of previous round will produce double tiny blocks. This is for extra time slot of previous round. expectedMiningTime = previousRound.GetExtraBlockMiningTime().AddMilliseconds(producedTinyBlocks - .Mul(miningInterval).Div(AElfConsensusContractConstants.TinyBlocksNumber)).ToTimestamp(); + .Mul(miningInterval).Div(AEDPoSContractConstants.TinyBlocksNumber)).ToTimestamp(); } nextBlockMiningLeftMilliseconds = @@ -192,7 +192,7 @@ private ConsensusCommand GetConsensusCommand(AElfConsensusBehaviour behaviour, R { ExpectedMiningTime = expectedMiningTime, NextBlockMiningLeftMilliseconds = nextBlockMiningLeftMilliseconds, - LimitMillisecondsOfMiningBlock = miningInterval / AElfConsensusContractConstants.TinyBlocksNumber, + LimitMillisecondsOfMiningBlock = miningInterval / AEDPoSContractConstants.TinyBlocksNumber, Hint = hint }; } diff --git a/src/AElf.Contracts.Consensus.AEDPoS/ViewMethods.cs b/src/AElf.Contracts.Consensus.AEDPoS/ViewMethods.cs index 12d7ac4ec3..71690583cc 100644 --- a/src/AElf.Contracts.Consensus.AEDPoS/ViewMethods.cs +++ b/src/AElf.Contracts.Consensus.AEDPoS/ViewMethods.cs @@ -621,8 +621,16 @@ private string GetNextAvailableMinerPublicKey(Round round) private int GetMinersCount() { - return ((int) Context.CurrentBlockTime.Subtract(State.BlockchainStartTimestamp.Value.ToDateTime()) - .TotalDays).Div(7); + if (TryToGetRoundInformation(1, out var firstRound)) + { + // TODO: Maybe this should according to date, like every July 1st we increase 2 miners. + var initialMinersCount = firstRound.RealTimeMinersInformation.Count; + return initialMinersCount.Add(((int) Context.CurrentBlockTime + .Subtract(State.BlockchainStartTimestamp.Value.ToDateTime()) + .TotalDays).Div(365).Mul(2)); + } + + return 0; } } } \ No newline at end of file diff --git a/src/AElf.Contracts.Election/ElectionContractState.cs b/src/AElf.Contracts.Election/ElectionContractState.cs index 6e118c4754..d772d509e4 100644 --- a/src/AElf.Contracts.Election/ElectionContractState.cs +++ b/src/AElf.Contracts.Election/ElectionContractState.cs @@ -50,6 +50,7 @@ public partial class ElectionContractState : ContractState public SingletonState TimeEachTerm { get; set; } public SingletonState MinerElectionVotingItemId { get; set; } - + + public SingletonState CachedWelfareWeight { get; set; } } } \ No newline at end of file diff --git a/src/AElf.Contracts.Election/ElectionContract_Treasury.cs b/src/AElf.Contracts.Election/ElectionContract_Treasury.cs index 633a12aa97..73e9ece517 100644 --- a/src/AElf.Contracts.Election/ElectionContract_Treasury.cs +++ b/src/AElf.Contracts.Election/ElectionContract_Treasury.cs @@ -205,8 +205,12 @@ private void ReleaseTreasurySubProfitItems(long termNumber) State.ProfitContract.ReleaseProfit.Send(new ReleaseProfitInput { ProfitId = State.WelfareHash.Value, - Period = termNumber > 1 ? termNumber - 1 : -1 + Period = termNumber > 1 ? termNumber - 1 : -1, + TotalWeight = State.CachedWelfareWeight.Value }); + + State.CachedWelfareWeight.Value = + State.ProfitContract.GetProfitItem.Call(State.WelfareHash.Value).TotalWeight; } private void UpdateTreasurySubItemsWeights(long termNumber) diff --git a/src/AElf.Contracts.Profit/ProfitContract.cs b/src/AElf.Contracts.Profit/ProfitContract.cs index 2c7b891307..957240eb60 100644 --- a/src/AElf.Contracts.Profit/ProfitContract.cs +++ b/src/AElf.Contracts.Profit/ProfitContract.cs @@ -51,6 +51,7 @@ public override Hash CreateProfitItem(CreateProfitItemInput input) { profitId = Hash.FromTwoHashes(profitId, createdProfitIds.Last()); } + State.ProfitItemsMap[profitId] = new ProfitItem { VirtualAddress = Context.ConvertVirtualAddressToContractAddress(profitId), @@ -75,7 +76,7 @@ public override Hash CreateProfitItem(CreateProfitItemInput input) } State.CreatedProfitItemsMap[Context.Sender] = createdProfitItems; - + Context.LogDebug(() => $"Created profit item {profitId}"); return profitId; } @@ -145,7 +146,7 @@ public override Empty AddWeight(AddWeightInput input) { return new Empty(); } - + Assert(input.EndPeriod >= profitItem.CurrentPeriod, "Invalid end period."); profitItem.TotalWeight += input.Weight; @@ -181,6 +182,8 @@ public override Empty AddWeight(AddWeightInput input) } State.ProfitDetailsMap[profitId][input.Receiver] = currentProfitDetails; + + Context.LogDebug(() => $"Add {input.Weight} weights to profit item {input.ProfitId.ToHex()}"); return new Empty(); } @@ -277,6 +280,8 @@ public override Empty ReleaseProfit(ReleaseProfitInput input) return new Empty(); } + var totalWeight = input.TotalWeight == 0 ? profitItem.TotalWeight : input.TotalWeight; + Assert(Context.Sender == profitItem.Creator, "Only creator can release profits."); var profitVirtualAddress = Context.ConvertVirtualAddressToContractAddress(input.ProfitId); @@ -294,17 +299,17 @@ public override Empty ReleaseProfit(ReleaseProfitInput input) input.Amount = balance; } - if (input.Period < 0 || profitItem.TotalWeight <= 0) + if (input.Period < 0 || totalWeight <= 0) { + profitItem.CurrentPeriod = input.Period > 0 ? input.Period.Add(1) : profitItem.CurrentPeriod; + // Release to an address no one can receive profits. - if (input.Amount <= 0) { + State.ProfitItemsMap[input.ProfitId] = profitItem; return new Empty(); } - profitItem.CurrentPeriod = input.Period > 0 ? input.Period.Add(1) : profitItem.CurrentPeriod; - if (input.Period >= 0) { input.Period = -1; @@ -320,7 +325,7 @@ public override Empty ReleaseProfit(ReleaseProfitInput input) Amount = input.Amount, Symbol = profitItem.TokenSymbol }); - profitItem.TotalAmount -= input.Amount; + profitItem.TotalAmount = profitItem.TotalAmount.Sub(input.Amount); State.ProfitItemsMap[input.ProfitId] = profitItem; return new Empty(); } @@ -328,7 +333,8 @@ public override Empty ReleaseProfit(ReleaseProfitInput input) // Update current_period. var releasingPeriod = profitItem.CurrentPeriod; - Assert(input.Period == releasingPeriod, $"Invalid period. When release profit item {input.ProfitId.ToHex()} of period {input.Period}"); + Assert(input.Period == releasingPeriod, + $"Invalid period. When release profit item {input.ProfitId.ToHex()} of period {input.Period}. Current period is {releasingPeriod}"); var profitsReceivingVirtualAddress = GetReleasedPeriodProfitsVirtualAddress(profitVirtualAddress, releasingPeriod); @@ -338,29 +344,33 @@ public override Empty ReleaseProfit(ReleaseProfitInput input) { releasedProfitInformation = new ReleasedProfitsInformation { - TotalWeight = profitItem.TotalWeight, + TotalWeight = totalWeight, ProfitsAmount = input.Amount, IsReleased = true }; } else { - releasedProfitInformation.TotalWeight = profitItem.TotalWeight; + releasedProfitInformation.TotalWeight = totalWeight; releasedProfitInformation.ProfitsAmount += input.Amount; releasedProfitInformation.IsReleased = true; } State.ReleasedProfitsMap[profitsReceivingVirtualAddress] = releasedProfitInformation; + Context.LogDebug(() => + $"Released profit information of {input.ProfitId.ToHex()} in period {input.Period}, " + + $"total weight {releasedProfitInformation.TotalWeight}, total amount {releasedProfitInformation.ProfitsAmount}"); + // Start releasing. - + var remainAmount = input.Amount; foreach (var subProfitItem in profitItem.SubProfitItems) { var subItemVirtualAddress = Context.ConvertVirtualAddressToContractAddress(subProfitItem.ProfitId); - var amount = subProfitItem.Weight.Mul(input.Amount).Div(profitItem.TotalWeight); + var amount = subProfitItem.Weight.Mul(input.Amount).Div(totalWeight); if (amount != 0) { State.TokenContract.TransferFrom.Send(new TransferFromInput @@ -468,6 +478,8 @@ public override Empty AddProfits(AddProfitsInput input) public override Empty Profit(ProfitInput input) { + Context.LogDebug(() => $"{Context.Sender} is trying to profit from {input.ProfitId.ToHex()}."); + var profitItem = State.ProfitItemsMap[input.ProfitId]; Assert(profitItem != null, "Profit item not found."); @@ -482,7 +494,8 @@ public override Empty Profit(ProfitInput input) var profitVirtualAddress = Context.ConvertVirtualAddressToContractAddress(input.ProfitId); - var availableDetails = profitDetails.Details.Where(d => d.LastProfitPeriod != profitItem.CurrentPeriod).ToList(); + var availableDetails = profitDetails.Details.Where(d => d.LastProfitPeriod != profitItem.CurrentPeriod) + .ToList(); for (var i = 0; i < Math.Min(ProfitContractConsts.ProfitLimit, availableDetails.Count); i++) { @@ -502,15 +515,18 @@ public override Empty Profit(ProfitInput input) var releasedProfitsVirtualAddress = GetReleasedPeriodProfitsVirtualAddress(profitVirtualAddress, period); var releasedProfitsInformation = State.ReleasedProfitsMap[releasedProfitsVirtualAddress]; - if (releasedProfitsInformation.IsReleased) + var amount = profitDetail.Weight.Mul(releasedProfitsInformation.ProfitsAmount) + .Div(releasedProfitsInformation.TotalWeight); + var period1 = period; + Context.LogDebug(() => $"{Context.Sender} is profiting {amount} tokens from {input.ProfitId.ToHex()} in period {period1}"); + if (releasedProfitsInformation.IsReleased && amount > 0) { State.TokenContract.TransferFrom.Send(new TransferFromInput { From = releasedProfitsVirtualAddress, To = Context.Sender, Symbol = profitItem.TokenSymbol, - Amount = profitDetail.Weight.Mul(releasedProfitsInformation.ProfitsAmount) - .Div(releasedProfitsInformation.TotalWeight) + Amount = amount }); } @@ -524,6 +540,5 @@ public override Empty Profit(ProfitInput input) return new Empty(); } - } -} +} \ No newline at end of file diff --git a/src/AElf.Contracts.Profit/ViewMethods.cs b/src/AElf.Contracts.Profit/ViewMethods.cs index 726fab9584..39273eb4e9 100644 --- a/src/AElf.Contracts.Profit/ViewMethods.cs +++ b/src/AElf.Contracts.Profit/ViewMethods.cs @@ -28,7 +28,8 @@ public override ReleasedProfitsInformation GetReleasedProfitsInformation( { var virtualAddress = Context.ConvertVirtualAddressToContractAddress(input.ProfitId); var releasedProfitsVirtualAddress = GetReleasedPeriodProfitsVirtualAddress(virtualAddress, input.Period); - return State.ReleasedProfitsMap[releasedProfitsVirtualAddress]; + return State.ReleasedProfitsMap[releasedProfitsVirtualAddress] ?? new ReleasedProfitsInformation + {ProfitsAmount = -1, TotalWeight = -1}; } public override ProfitDetails GetProfitDetails(GetProfitDetailsInput input) diff --git a/src/AElf.OS/Jobs/BlockSyncJob.cs b/src/AElf.OS/Jobs/BlockSyncJob.cs index 38862a5971..5c2b32304b 100644 --- a/src/AElf.OS/Jobs/BlockSyncJob.cs +++ b/src/AElf.OS/Jobs/BlockSyncJob.cs @@ -17,7 +17,6 @@ public class BlockSyncJob { private const long InitialSyncLimit = 10; private const int BlockSyncJobLimit = 200; - private const int BlockSyncWaitTime = 5000; private readonly IBlockchainService _blockchainService; private readonly INetworkService _networkService; @@ -84,8 +83,7 @@ public async Task ExecuteAsync(BlockSyncJobArgs args) if (chain.LongestChainHeight < blockHeight - BlockSyncJobLimit) { Logger.LogWarning($"Pause sync task and wait for synced block to be processed, best chain height: {chain.BestChainHeight}"); - await Task.Delay(BlockSyncWaitTime); - continue; + break; } Logger.LogDebug($"Request blocks start with {blockHash}"); diff --git a/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElfConsensusContractTestBase.cs b/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElfConsensusContractTestBase.cs index 26c17c74bf..5f26d2bc69 100644 --- a/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElfConsensusContractTestBase.cs +++ b/test/AElf.Contracts.Consensus.AEDPoS.Tests/AElfConsensusContractTestBase.cs @@ -40,7 +40,7 @@ public class AElfConsensusContractTestBase : ContractTestBase> ElectionContract_ReleaseTreasuryProfits_Relea ProfitId = ProfitItemsIds[ProfitType.CitizenWelfare], Period = 1 }); - releasedProfitsInformation.TotalWeight.ShouldBe(0); - releasedProfitsInformation.ProfitsAmount.ShouldBe(0); + releasedProfitsInformation.TotalWeight.ShouldBe(-1); + releasedProfitsInformation.ProfitsAmount.ShouldBe(-1); releasedProfitsInformation.IsReleased.ShouldBe(false); // Check balance of virtual address. @@ -190,8 +190,8 @@ await ProfitContractStub.GetReleasedProfitsInformation.CallAsync( ProfitId = ProfitItemsIds[ProfitType.BasicMinerReward], Period = 1 }); - releasedProfitsInformation.TotalWeight.ShouldBe(0); - releasedProfitsInformation.ProfitsAmount.ShouldBe(0); + releasedProfitsInformation.TotalWeight.ShouldBe(-1); + releasedProfitsInformation.ProfitsAmount.ShouldBe(-1); releasedProfitsInformation.IsReleased.ShouldBe(false); } @@ -234,8 +234,8 @@ await ProfitContractStub.GetReleasedProfitsInformation.CallAsync( ProfitId = ProfitItemsIds[ProfitType.VotesWeightReward], Period = 1 }); - releasedProfitsInformation.TotalWeight.ShouldBe(0); - releasedProfitsInformation.ProfitsAmount.ShouldBe(0); + releasedProfitsInformation.TotalWeight.ShouldBe(-1); + releasedProfitsInformation.ProfitsAmount.ShouldBe(-1); releasedProfitsInformation.IsReleased.ShouldBe(false); } @@ -277,8 +277,8 @@ await ProfitContractStub.GetReleasedProfitsInformation.CallAsync( ProfitId = ProfitItemsIds[ProfitType.ReElectionReward], Period = 1 }); - releasedProfitsInformation.TotalWeight.ShouldBe(0); - releasedProfitsInformation.ProfitsAmount.ShouldBe(0); + releasedProfitsInformation.TotalWeight.ShouldBe(-1); + releasedProfitsInformation.ProfitsAmount.ShouldBe(-1); releasedProfitsInformation.IsReleased.ShouldBe(false); } @@ -291,8 +291,8 @@ await ProfitContractStub.GetReleasedProfitsInformation.CallAsync( ProfitId = ProfitItemsIds[ProfitType.ReElectionReward], Period = 1 }); - releasedProfitsInformation.TotalWeight.ShouldBe(0); - releasedProfitsInformation.ProfitsAmount.ShouldBe(0); + releasedProfitsInformation.TotalWeight.ShouldBe(-1); + releasedProfitsInformation.ProfitsAmount.ShouldBe(-1); releasedProfitsInformation.IsReleased.ShouldBe(false); } @@ -456,7 +456,7 @@ await VoteToCandidates(VotersKeyPairs.Take(1).ToList(), // Already burned. profitItems[ProfitType.BasicMinerReward].TotalAmount.ShouldBe(0); // Each new miner takes 1 weight. - profitItems[ProfitType.BasicMinerReward].TotalWeight.ShouldBeLessThan(candidatesKeyPairs.Count); + profitItems[ProfitType.BasicMinerReward].TotalWeight.ShouldBe(5); // Check released profit information. // We don't give initial miners rewards. @@ -468,7 +468,7 @@ await ProfitContractStub.GetReleasedProfitsInformation.CallAsync( ProfitId = ProfitItemsIds[ProfitType.BasicMinerReward], Period = 2 }); - releasedProfitsInformation.TotalWeight.ShouldBe(profitItems[ProfitType.BasicMinerReward].TotalWeight); + releasedProfitsInformation.TotalWeight.ShouldBeLessThan(candidatesKeyPairs.Count); releasedProfitsInformation.ProfitsAmount.ShouldBe(releasedAmount .Mul(ElectionContractConstants.MinerRewardWeight) .Div(totalWeightsOfTreasury) @@ -721,7 +721,7 @@ public async Task ElectionContract_ReleaseTreasuryProfits_ReleaseThirdTerm() // Already burned. profitItems[ProfitType.BasicMinerReward].TotalAmount.ShouldBe(0); // Each new miner takes 1 weight. - profitItems[ProfitType.BasicMinerReward].TotalWeight.ShouldBeLessThan(candidatesKeyPairs.Count); + profitItems[ProfitType.BasicMinerReward].TotalWeight.ShouldBe(5); // Check released profit information. // We don't give initial miners rewards.