Skip to content

Commit

Permalink
Merge pull request #1705 from AElfProject/fix/economic-system
Browse files Browse the repository at this point in the history
Fix economic system bugs.
  • Loading branch information
rosona authored May 15, 2019
2 parents b70ee02 + 7cec5c0 commit 3bcd093
Show file tree
Hide file tree
Showing 13 changed files with 82 additions and 54 deletions.
1 change: 1 addition & 0 deletions protobuf/profit_contract.proto
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ message ReleaseProfitInput {
Hash profit_id = 1;
sint64 period = 2;
sint64 amount = 3;
sint64 total_weight = 4;
}

message ProfitDetails {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
});
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace AElf.Contracts.Consensus.AEDPoS
{
public static class AElfConsensusContractConstants
public static class AEDPoSContractConstants
{
public const int TinyBlocksNumber = 8;
}
Expand Down
16 changes: 8 additions & 8 deletions src/AElf.Contracts.Consensus.AEDPoS/HelpMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -192,7 +192,7 @@ private ConsensusCommand GetConsensusCommand(AElfConsensusBehaviour behaviour, R
{
ExpectedMiningTime = expectedMiningTime,
NextBlockMiningLeftMilliseconds = nextBlockMiningLeftMilliseconds,
LimitMillisecondsOfMiningBlock = miningInterval / AElfConsensusContractConstants.TinyBlocksNumber,
LimitMillisecondsOfMiningBlock = miningInterval / AEDPoSContractConstants.TinyBlocksNumber,
Hint = hint
};
}
Expand Down
12 changes: 10 additions & 2 deletions src/AElf.Contracts.Consensus.AEDPoS/ViewMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
3 changes: 2 additions & 1 deletion src/AElf.Contracts.Election/ElectionContractState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public partial class ElectionContractState : ContractState
public SingletonState<int> TimeEachTerm { get; set; }

public SingletonState<Hash> MinerElectionVotingItemId { get; set; }


public SingletonState<long> CachedWelfareWeight { get; set; }
}
}
6 changes: 5 additions & 1 deletion src/AElf.Contracts.Election/ElectionContract_Treasury.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
51 changes: 33 additions & 18 deletions src/AElf.Contracts.Profit/ProfitContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -75,7 +76,7 @@ public override Hash CreateProfitItem(CreateProfitItemInput input)
}

State.CreatedProfitItemsMap[Context.Sender] = createdProfitItems;

Context.LogDebug(() => $"Created profit item {profitId}");
return profitId;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -320,15 +325,16 @@ 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();
}

// 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);
Expand All @@ -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
Expand Down Expand Up @@ -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.");

Expand All @@ -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++)
{
Expand All @@ -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
});
}

Expand All @@ -524,6 +540,5 @@ public override Empty Profit(ProfitInput input)

return new Empty();
}

}
}
}
3 changes: 2 additions & 1 deletion src/AElf.Contracts.Profit/ViewMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions src/AElf.OS/Jobs/BlockSyncJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class AElfConsensusContractTestBase : ContractTestBase<AEDPoSContractTest

protected const int MiningInterval = 4000;

protected const int SmallBlockMiningInterval = 500;
protected static int SmallBlockMiningInterval = MiningInterval.Div(AEDPoSContractConstants.TinyBlocksNumber);

protected const long DaysEachTerm = 7;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public async Task AElfConsensusContract_UpdateValueInFirstRound()
var command = await BootMiner.GetConsensusCommand.CallAsync(new CommandInput
{PublicKey = ByteString.CopyFrom(BootMinerKeyPair.PublicKey)});
command.NextBlockMiningLeftMilliseconds.ShouldBe(MiningInterval);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AElfConsensusContractConstants.TinyBlocksNumber);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AEDPoSContractConstants.TinyBlocksNumber);
command.Hint.ShouldBe(new AElfConsensusHint
{Behaviour = AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue}
.ToByteArray());
Expand All @@ -52,7 +52,7 @@ public async Task AElfConsensusContract_UpdateValueInFirstRound()
{PublicKey = ByteString.CopyFrom(otherMinerKeyPair.PublicKey)});
command.NextBlockMiningLeftMilliseconds.ShouldBe(
MiningInterval * InitialMinersCount + MiningInterval * order);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AElfConsensusContractConstants.TinyBlocksNumber);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AEDPoSContractConstants.TinyBlocksNumber);
command.Hint.ShouldBe(new AElfConsensusHint {Behaviour = AElfConsensusBehaviour.NextRound}
.ToByteArray());
}
Expand Down Expand Up @@ -89,7 +89,7 @@ public async Task AElfConsensusContract_Process()
var command = await miner.GetConsensusCommand.CallAsync(new CommandInput
{PublicKey = ByteString.CopyFrom(minerKeyPair.PublicKey)});
command.NextBlockMiningLeftMilliseconds.ShouldBe(leftMilliseconds);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AElfConsensusContractConstants.TinyBlocksNumber);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AEDPoSContractConstants.TinyBlocksNumber);
command.Hint.ShouldBe(new AElfConsensusHint {Behaviour = AElfConsensusBehaviour.UpdateValue}
.ToByteArray());
}
Expand Down Expand Up @@ -117,7 +117,7 @@ public async Task AElfConsensusContract_Process()
command.NextBlockMiningLeftMilliseconds.ShouldBe(leftMilliseconds);
}

command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AElfConsensusContractConstants.TinyBlocksNumber);
command.LimitMillisecondsOfMiningBlock.ShouldBe(MiningInterval / AEDPoSContractConstants.TinyBlocksNumber);
command.Hint.ShouldBe(new AElfConsensusHint {Behaviour = AElfConsensusBehaviour.NextRound}
.ToByteArray());
}
Expand Down
Loading

0 comments on commit 3bcd093

Please sign in to comment.