Skip to content

Commit

Permalink
Fix test
Browse files Browse the repository at this point in the history
  • Loading branch information
BrandonWeng committed Apr 25, 2023
1 parent 1cbc823 commit 76c2d92
Show file tree
Hide file tree
Showing 10 changed files with 560 additions and 96 deletions.
3 changes: 2 additions & 1 deletion scripts/old_initialize_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ python3 loadtest/scripts/populate_genesis_accounts.py 50 loc
~/go/bin/seid collect-gentxs
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["max_deposit_period"]="300s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="5s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq --arg release_date "$(date +"%Y-%m-%d")" '.app_state["mint"]["params"]["token_release_schedule"]=[{"date": $release_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq --arg start_date "$(date +"%Y-%m-%d")" --arg end_date "$(date -v+3d +"%Y-%m-%d")" '.app_state["mint"]["params"]["token_release_schedule"]=[{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq --arg start_date "$(date -v+3d +"%Y-%m-%d")" --arg end_date "$(date -v+5d +"%Y-%m-%d")" '.app_state["mint"]["params"]["token_release_schedule"] += [{"start_date": $start_date, "end_date": $end_date, "token_release_amount": "999999999999"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq '.app_state["gov"]["voting_params"]["expedited_voting_period"]="4s"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["vote_period"]="1"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
cat ~/.sei/config/genesis.json | jq '.app_state["distribution"]["params"]["community_tax"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json
Expand Down
7 changes: 4 additions & 3 deletions x/mint/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func (k Keeper) BeforeEpochStart(ctx sdk.Context, epoch epochTypes.Epoch) {

func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) {
latestMinter := k.GetOrUpdateLatestMinter(ctx, epoch)
coinsToMint := latestMinter.GetReleaseAmountToday()
coinsToMint := latestMinter.GetReleaseAmountToday(epoch.CurrentEpochStartTime)

if coinsToMint.IsZero() {
k.Logger(ctx).Debug("No coins to mint", "minter", latestMinter)
Expand All @@ -27,8 +27,9 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epoch epochTypes.Epoch) {
}

// Released Succssfully, decrement the remaining amount by the daily release amount and update minter
latestMinter.RecordSuccessfulMint(ctx, epoch)
k.SetMinter(ctx, latestMinter)
amountMinted := coinsToMint.AmountOf(latestMinter.GetDenom())
updatedMinter := latestMinter.RecordSuccessfulMint(ctx, epoch, amountMinted.Uint64())
k.SetMinter(ctx, updatedMinter)
}

type Hooks struct {
Expand Down
322 changes: 271 additions & 51 deletions x/mint/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,63 +32,225 @@ func getEpoch(genesisTime time.Time, currTime time.Time) types.Epoch {
}

func TestEndOfEpochMintedCoinDistribution(t *testing.T) {
seiApp := keepertest.TestApp()
ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()})
ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey))))
t.Parallel()

genesisTime := time.Date(2022, time.Month(7), 18, 10, 0, 0, 0, time.UTC)
t.Run("Initial should be zero", func(t *testing.T) {
seiApp := keepertest.TestApp()
ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()})
ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey))))

tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{
{
StartDate: genesisTime.AddDate(1, 0, 0).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(1, 60, 0).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
{
StartDate: genesisTime.AddDate(2, 0, 0).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(3, 0, 0).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 1250000,
},
}
mintParams := minttypes.NewParams(
"usei",
tokenReleaseSchedle,
)
header := tmproto.Header{
Height: seiApp.LastBlockHeight() + 1,
Time: time.Now().UTC(),
}
seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header})
require.Equal(t, int64(0), seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin().Amount.Int64())
})

seiApp.MintKeeper.SetParams(ctx, mintParams)
t.Run("even full release", func(t *testing.T) {
seiApp := keepertest.TestApp()
ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()})
ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey))))

header := tmproto.Header{Height: seiApp.LastBlockHeight() + 1}
seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header})
header := tmproto.Header{
Height: seiApp.LastBlockHeight() + 1,
Time: time.Now().UTC(),
}
seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header})
genesisTime := header.Time
tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{
{
StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 25).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
}
mintParams := minttypes.NewParams(
"usei",
tokenReleaseSchedle,
)
seiApp.MintKeeper.SetParams(ctx, mintParams)

// Year 1
currTime := genesisTime.AddDate(1, 0, 0)
currEpoch := getEpoch(genesisTime, currTime)
presupply := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom)
for i := 0; i < 25; i++ {
currTime := genesisTime.AddDate(0, 0, i)
currEpoch := getEpoch(genesisTime, currTime)
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

// 250k / 25 days = 100000 per day
expectedAmount := int64(100000)
newMinter := seiApp.MintKeeper.GetMinter(ctx)

if i == 25 {
require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero")
break
}

require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct")
require.Equal(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), "Minted amount should be correct")
require.Equal(t, int64(2500000 - expectedAmount * int64(i+1)), int64(newMinter.GetRemainingMintAmount()), "Remaining amount should be correct")
}
})

t.Run("uneven full release", func(t *testing.T) {
seiApp := keepertest.TestApp()
ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()})
ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey))))

header := tmproto.Header{
Height: seiApp.LastBlockHeight() + 1,
Time: time.Now().UTC(),
}
seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header})
genesisTime := header.Time

tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{
{
StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
}
mintParams := minttypes.NewParams(
"usei",
tokenReleaseSchedle,
)
seiApp.MintKeeper.SetParams(ctx, mintParams)

for i := 0; i < 25; i++ {
currTime := genesisTime.AddDate(0, 0, i)
currEpoch := getEpoch(genesisTime, currTime)
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

expectedAmount := int64(104166)
newMinter := seiApp.MintKeeper.GetMinter(ctx)

// Uneven distribution still results in 250k total distributed
if i == 24 {
require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero")
break
}

require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct")
require.InDelta(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct")
require.InDelta(t, int64(2500000 - expectedAmount * int64(i+1)), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct")
}
})

t.Run("multiple full releases", func(t *testing.T) {
seiApp := keepertest.TestApp()
ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()})
ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey))))

header := tmproto.Header{
Height: seiApp.LastBlockHeight() + 1,
Time: time.Now().UTC(),
}
seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header})
genesisTime := header.Time

tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{
{
StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
{
StartDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
{
StartDate: genesisTime.AddDate(0, 0, 30).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 40).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
{
StartDate: genesisTime.AddDate(0, 0, 45).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 50).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
}
mintParams := minttypes.NewParams(
"usei",
tokenReleaseSchedle,
)
seiApp.MintKeeper.SetParams(ctx, mintParams)

for i := 0; i < 50; i++ {
currTime := genesisTime.AddDate(0, 0, i)
currEpoch := getEpoch(genesisTime, currTime)
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

// Run hooks
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

// Year 1
mintedCoinYear1 := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin()
postsupplyYear1 := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom)
require.True(t, postsupplyYear1.IsEqual(presupply.Add(mintedCoinYear1)))
require.Equal(t, mintedCoinYear1.Amount.Int64(), int64(2500000))

// Year 2
currTime = currTime.AddDate(1, 0, 0)
currEpoch = getEpoch(genesisTime, currTime)

// Run hooks
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

mintedCoinYear2 := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin()
postsupplyYear2 := seiApp.BankKeeper.GetSupply(ctx, mintParams.MintDenom)
require.True(t, postsupplyYear2.IsEqual(postsupplyYear1.Add(mintedCoinYear2)))
require.Equal(t, mintedCoinYear2.Amount.Int64(), int64(1250000))
newMinter := seiApp.MintKeeper.GetMinter(ctx)

// Should be zero by the end of each release and when there's no release scheduled
if i == 23 || i == 29 || i == 39 || i == 49 || (i >= 40 && i < 45) {
require.Zero(t, newMinter.GetRemainingMintAmount(), "Remaining amount should be zero at %s", currTime.Format(minttypes.TokenReleaseDateFormat))
continue
}

require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct")
}
})

t.Run("outage during release", func(t *testing.T) {
seiApp := keepertest.TestApp()
ctx := seiApp.BaseApp.NewContext(false, tmproto.Header{Time: time.Now()})
ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, dexcache.NewMemState(seiApp.GetKey(types.StoreKey))))

header := tmproto.Header{
Height: seiApp.LastBlockHeight() + 1,
Time: time.Now().UTC(),
}
seiApp.BeginBlock(ctx, abci.RequestBeginBlock{Header: header})
genesisTime := header.Time

tokenReleaseSchedle := []minttypes.ScheduledTokenRelease{
{
StartDate: genesisTime.AddDate(0, 0, 0).Format(minttypes.TokenReleaseDateFormat),
EndDate: genesisTime.AddDate(0, 0, 24).Format(minttypes.TokenReleaseDateFormat),
TokenReleaseAmount: 2500000,
},
}
mintParams := minttypes.NewParams(
"usei",
tokenReleaseSchedle,
)
seiApp.MintKeeper.SetParams(ctx, mintParams)

for i := 0; i < 13; i++ {
currTime := genesisTime.AddDate(0, 0, i)
currEpoch := getEpoch(genesisTime, currTime)
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

newMinter := seiApp.MintKeeper.GetMinter(ctx)
expectedAmount := int64(104166)

require.Equal(t, currTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct")
require.InDelta(t, expectedAmount, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct")
require.InDelta(t, int64(2500000 - expectedAmount * int64(i+1)), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct")
}

// 3 day outage
postOutageTime := genesisTime.AddDate(0, 0, 15)
currEpoch := getEpoch(genesisTime, postOutageTime)
seiApp.EpochKeeper.BeforeEpochStart(ctx, currEpoch)
seiApp.EpochKeeper.AfterEpochEnd(ctx, currEpoch)
mintParams = seiApp.MintKeeper.GetParams(ctx)

newMinter := seiApp.MintKeeper.GetMinter(ctx)
require.Equal(t, postOutageTime.Format(minttypes.TokenReleaseDateFormat), newMinter.GetLastMintDate(), "Last mint date should be correct")
require.InDelta(t, 127315, newMinter.GetLastMintAmountCoin().Amount.Int64(), 1, "Minted amount should be correct")
require.InDelta(t, int64(1018522), int64(newMinter.GetRemainingMintAmount()), 24, "Remaining amount should be correct")
})
}

func TestNoEpochPassedNoDistribution(t *testing.T) {
Expand Down Expand Up @@ -118,3 +280,61 @@ func TestNoEpochPassedNoDistribution(t *testing.T) {
endLastMintAmount := seiApp.MintKeeper.GetMinter(ctx).GetLastMintAmountCoin()
require.True(t, startLastMintAmount.Equal(endLastMintAmount))
}

func TestSortTokenReleaseCalendar(t *testing.T) {
testCases := []struct {
name string
input []minttypes.ScheduledTokenRelease
expectedOutput []minttypes.ScheduledTokenRelease
}{
{
name: "Empty schedule",
input: []minttypes.ScheduledTokenRelease{},
expectedOutput: []minttypes.ScheduledTokenRelease{},
},
{
name: "Already sorted schedule",
input: []minttypes.ScheduledTokenRelease{
{StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100},
{StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200},
{StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300},
},
expectedOutput: []minttypes.ScheduledTokenRelease{
{StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100},
{StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200},
{StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300},
},
},
{
name: "Unsorted schedule",
input: []minttypes.ScheduledTokenRelease{
{StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300},
{StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100},
{StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200},
},
expectedOutput: []minttypes.ScheduledTokenRelease{
{StartDate: "2023-04-01", EndDate: "2023-04-10", TokenReleaseAmount: 100},
{StartDate: "2023-04-11", EndDate: "2023-04-20", TokenReleaseAmount: 200},
{StartDate: "2023-04-21", EndDate: "2023-04-30", TokenReleaseAmount: 300},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
sorted := minttypes.SortTokenReleaseCalendar(tc.input)

if len(sorted) != len(tc.expectedOutput) {
t.Fatalf("Expected output length to be %d, but got %d", len(tc.expectedOutput), len(sorted))
}

for i, expected := range tc.expectedOutput {
if sorted[i].StartDate != expected.StartDate ||
sorted[i].EndDate != expected.EndDate ||
sorted[i].TokenReleaseAmount != expected.TokenReleaseAmount {
t.Errorf("Expected token release at index %d to be %+v, but got %+v", i, expected, sorted[i])
}
}
})
}
}
13 changes: 9 additions & 4 deletions x/mint/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,10 @@ func (k Keeper) GetOrUpdateLatestMinter(
params := k.GetParams(ctx)
currentReleaseMinter := k.GetMinter(ctx)
nextScheduledRelease := GetNextScheduledTokenRelease(epoch, params.TokenReleaseSchedule, currentReleaseMinter)

// There's still an ongoing release
if currentReleaseMinter.OngoingRelease() || nextScheduledRelease == nil {
k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter, "nextScheduledRelease", nextScheduledRelease)
k.Logger(ctx).Debug("Ongoing token release or no nextScheduledRelease", "minter", currentReleaseMinter)
return currentReleaseMinter
}

Expand All @@ -159,9 +160,13 @@ func GetNextScheduledTokenRelease(
// This should not happen as the scheduled release date is validated when the param is updated
panic(fmt.Errorf("invalid scheduled release date: %s", err))
}
// If blocktime is after the currentScheduled date and it's after the current release
if epoch.GetCurrentEpochStartTime().After(scheduledStartDate) && scheduledStartDate.After(currentMinter.GetEndDateTime()) {
return &scheduledRelease
scheduledStartDateTime := scheduledStartDate.UTC()

// If epoch is after the currentScheduled date and it's after the current release
if epoch.GetCurrentEpochStartTime().After(scheduledStartDateTime) {
if scheduledStartDateTime.After(currentMinter.GetEndDateTime()) || scheduledStartDateTime.Equal(currentMinter.GetEndDateTime()) {
return &scheduledRelease
}
}
}
return nil
Expand Down
Loading

0 comments on commit 76c2d92

Please sign in to comment.