update endblocker test

This commit is contained in:
rhuairahrighairigh 2019-12-28 22:00:04 +00:00
parent 0d72f47bc2
commit 8a4109ff26
8 changed files with 70 additions and 60 deletions

View File

@ -4,40 +4,53 @@ import (
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/auction" "github.com/kava-labs/kava/x/auction"
"github.com/kava-labs/kava/x/liquidator"
) )
func TestKeeper_EndBlocker(t *testing.T) { func TestKeeper_EndBlocker(t *testing.T) {
// Setup // Setup
_, addrs := app.GeneratePrivKeyAddressPairs(1) _, addrs := app.GeneratePrivKeyAddressPairs(2)
seller := addrs[0] buyer := addrs[0]
recipient := addrs[1]
sellerModName := liquidator.ModuleName
//sellerAddr := supply.NewModuleAddress(sellerModName)
tApp := app.NewTestApp() tApp := app.NewTestApp()
sellerAcc := supply.NewEmptyModuleAccount(sellerModName)
require.NoError(t, sellerAcc.SetCoins(cs(c("token1", 100), c("token2", 100))))
tApp.InitializeFromGenesisStates( tApp.InitializeFromGenesisStates(
app.NewAuthGenState(addrs, []sdk.Coins{cs(c("token1", 100), c("token2", 100))}), NewAuthGenStateFromAccs(authexported.GenesisAccounts{
auth.NewBaseAccount(buyer, cs(c("token1", 100), c("token2", 100)), nil, 0, 0),
sellerAcc,
}),
) )
ctx := tApp.NewContext(true, abci.Header{}) ctx := tApp.NewContext(true, abci.Header{})
keeper := tApp.GetAuctionKeeper() keeper := tApp.GetAuctionKeeper()
auctionID, err := keeper.StartForwardAuction(ctx, seller, c("token1", 20), c("token2", 0)) auctionID, err := keeper.StartForwardReverseAuction(ctx, sellerModName, c("token1", 20), c("token2", 50), recipient)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, keeper.PlaceBid(ctx, auctionID, buyer, c("token2", 30), c("token1", 20)))
// Run the endblocker, simulating a block height just before auction expiry // Run the endblocker, simulating a block time 1ns before auction expiry
preExpiryHeight := ctx.BlockHeight() + int64(auction.DefaultMaxAuctionDuration) - 1 preExpiryTime := ctx.BlockTime().Add(auction.DefaultBidDuration - 1)
auction.EndBlocker(ctx.WithBlockHeight(preExpiryHeight), keeper) auction.EndBlocker(ctx.WithBlockTime(preExpiryTime), keeper)
// Check auction has not been closed yet // Check auction has not been closed yet
_, found := keeper.GetAuction(ctx, auctionID) _, found := keeper.GetAuction(ctx, auctionID)
require.True(t, found) require.True(t, found)
// Run the endblocker, simulating a block height just after auction expiry // Run the endblocker, simulating a block time equal to auction expiry
expiryHeight := preExpiryHeight + 1 expiryTime := ctx.BlockTime().Add(auction.DefaultBidDuration)
auction.EndBlocker(ctx.WithBlockHeight(expiryHeight), keeper) auction.EndBlocker(ctx.WithBlockTime(expiryTime), keeper)
// Check auction has been closed // Check auction has been closed
_, found = keeper.GetAuction(ctx, auctionID) _, found = keeper.GetAuction(ctx, auctionID)
@ -46,3 +59,8 @@ func TestKeeper_EndBlocker(t *testing.T) {
func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) } func c(denom string, amount int64) sdk.Coin { return sdk.NewInt64Coin(denom, amount) }
func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) } func cs(coins ...sdk.Coin) sdk.Coins { return sdk.NewCoins(coins...) }
func NewAuthGenStateFromAccs(accounts authexported.GenesisAccounts) app.GenesisState {
authGenesis := auth.NewGenesisState(auth.DefaultParams(), accounts)
return app.GenesisState{auth.ModuleName: auth.ModuleCdc.MustMarshalJSON(authGenesis)}
}

View File

@ -16,7 +16,7 @@ const (
RouterKey = types.RouterKey RouterKey = types.RouterKey
DefaultParamspace = types.DefaultParamspace DefaultParamspace = types.DefaultParamspace
DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration DefaultMaxAuctionDuration = types.DefaultMaxAuctionDuration
DefaultMaxBidDuration = types.DefaultMaxBidDuration DefaultBidDuration = types.DefaultBidDuration
QueryGetAuction = types.QueryGetAuction QueryGetAuction = types.QueryGetAuction
) )

View File

@ -1,14 +0,0 @@
/*
Package auction is a module for creating generic auctions and allowing users to place bids until a timeout is reached.
TODO
- investigate when exactly auctions close and verify queue/endblocker logic is ok
- add more test cases, add stronger validation to user inputs
- add minimum bid increment
- decided whether to put auction params like default timeouts into the auctions themselves
- add docs
- Add constants for the module and route names
- user facing things like cli, rest, querier, tags
- custom error types, codespace
*/
package auction

View File

@ -9,7 +9,7 @@ import (
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
// StartForwardAuction starts a normal auction. // StartForwardAuction starts a normal auction that mints the sold coins.
func (k Keeper) StartForwardAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (types.ID, sdk.Error) { func (k Keeper) StartForwardAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (types.ID, sdk.Error) {
// create auction // create auction
auction := types.NewForwardAuction(seller, lot, bidDenom, ctx.BlockTime().Add(types.DefaultMaxAuctionDuration)) auction := types.NewForwardAuction(seller, lot, bidDenom, ctx.BlockTime().Add(types.DefaultMaxAuctionDuration))
@ -108,7 +108,12 @@ func (k Keeper) PlaceBid(ctx sdk.Context, auctionID types.ID, bidder sdk.AccAddr
} }
// store updated auction // store updated auction
k.SetAuction(ctx, a) // TODO maybe move into above funcs existing, found := k.GetAuction(ctx, a.GetID())
if found {
k.RemoveFromQueue(ctx, existing.GetEndTime(), existing.GetID())
}
k.SetAuction(ctx, a)
k.InsertIntoQueue(ctx, a.GetEndTime(), a.GetID())
return nil return nil
} }
@ -149,7 +154,7 @@ func (k Keeper) PlaceBidForward(ctx sdk.Context, a types.ForwardAuction, bidder
a.Bidder = bidder a.Bidder = bidder
a.Bid = bid a.Bid = bid
// increment timeout // increment timeout
a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration), a.MaxEndTime) // TODO write a min func for time types a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime)
return a, nil return a, nil
} }
@ -211,7 +216,7 @@ func (k Keeper) PlaceBidForwardReverse(ctx sdk.Context, a types.ForwardReverseAu
a.Lot = lot a.Lot = lot
a.Bid = bid a.Bid = bid
// increment timeout // increment timeout
a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration), a.MaxEndTime) a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime)
return a, nil return a, nil
} }
@ -245,7 +250,7 @@ func (k Keeper) PlaceBidReverse(ctx sdk.Context, a types.ReverseAuction, bidder
a.Bidder = bidder a.Bidder = bidder
a.Lot = lot a.Lot = lot
// increment timeout // increment timeout
a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration), a.MaxEndTime) a.EndTime = earliestTime(ctx.BlockTime().Add(types.DefaultBidDuration), a.MaxEndTime)
return a, nil return a, nil
} }
@ -282,6 +287,7 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID types.ID) sdk.Error {
// Delete auction from store (and queue) // Delete auction from store (and queue)
k.DeleteAuction(ctx, auctionID) k.DeleteAuction(ctx, auctionID)
k.RemoveFromQueue(ctx, auction.GetEndTime(), auction.GetID())
return nil return nil
} }
@ -297,7 +303,6 @@ func (k Keeper) MintAndPayoutAuctionLot(ctx sdk.Context, a types.ReverseAuction)
return nil return nil
} }
func (k Keeper) PayoutAuctionLot(ctx sdk.Context, a types.Auction) sdk.Error { func (k Keeper) PayoutAuctionLot(ctx sdk.Context, a types.Auction) sdk.Error {
// TODO this function is responsible for the addition of GetBidder and GetLot to auction interface. Could be split in to two funcs that operate on concrete auction types
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.GetBidder(), sdk.NewCoins(a.GetLot())) err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.GetBidder(), sdk.NewCoins(a.GetLot()))
if err != nil { if err != nil {
return err return err

View File

@ -48,7 +48,7 @@ func TestForwardAuctionBasic(t *testing.T) {
tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100))) tApp.CheckBalance(t, ctx, sellerAddr, cs(c("token1", 80), c("token2", 100)))
// Close auction at just at auction expiry time // Close auction at just at auction expiry time
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration)) ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultBidDuration))
require.NoError(t, keeper.CloseAuction(ctx, auctionID)) require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// Check buyer's coins increased // Check buyer's coins increased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90))) tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 120), c("token2", 90)))
@ -86,7 +86,7 @@ func TestReverseAuctionBasic(t *testing.T) {
tApp.CheckBalance(t, ctx, buyerAddr, cs(c("token1", 20))) tApp.CheckBalance(t, ctx, buyerAddr, cs(c("token1", 20)))
// Close auction at just after auction expiry // Close auction at just after auction expiry
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration)) ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultBidDuration))
require.NoError(t, keeper.CloseAuction(ctx, auctionID)) require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// Check seller's coins increased // Check seller's coins increased
tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110))) tApp.CheckBalance(t, ctx, seller, cs(c("token1", 80), c("token2", 110)))
@ -138,7 +138,7 @@ func TestForwardReverseAuctionBasic(t *testing.T) {
tApp.CheckBalance(t, ctx, recipient, cs(c("token1", 105), c("token2", 100))) tApp.CheckBalance(t, ctx, recipient, cs(c("token1", 105), c("token2", 100)))
// Close auction at just after auction expiry // Close auction at just after auction expiry
ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultMaxBidDuration)) ctx = ctx.WithBlockTime(ctx.BlockTime().Add(types.DefaultBidDuration))
require.NoError(t, keeper.CloseAuction(ctx, auctionID)) require.NoError(t, keeper.CloseAuction(ctx, auctionID))
// Check buyer's coins increased // Check buyer's coins increased
tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 115), c("token2", 50))) tApp.CheckBalance(t, ctx, buyer, cs(c("token1", 115), c("token2", 50)))

View File

@ -66,6 +66,7 @@ func (k Keeper) storeNewAuction(ctx sdk.Context, auction types.Auction) (types.I
auction = auction.WithID(newAuctionID) auction = auction.WithID(newAuctionID)
k.SetAuction(ctx, auction) k.SetAuction(ctx, auction)
k.InsertIntoQueue(ctx, auction.GetEndTime(), auction.GetID())
err = k.IncrementNextAuctionID(ctx) err = k.IncrementNextAuctionID(ctx)
if err != nil { if err != nil {

View File

@ -94,40 +94,40 @@ func TestIterateAuctionsByTime(t *testing.T) {
keeper := tApp.GetAuctionKeeper() keeper := tApp.GetAuctionKeeper()
ctx := tApp.NewContext(true, abci.Header{}) ctx := tApp.NewContext(true, abci.Header{})
// create a list of times // setup byTime index
queue := []struct { byTimeIndex := []struct {
endTime time.Time endTime time.Time
auctionID types.ID auctionID types.ID
}{ }{
{time.Date(84, time.January, 1, 0, 0, 0, 0, time.UTC), 34345345}, {time.Date(0, time.January, 1, 0, 0, 0, 0, time.UTC), 9999}, // distant past
{time.Date(98, time.January, 2, 0, 0, 0, 0, time.UTC), 5}, {time.Date(1998, time.January, 1, 11, 59, 59, 999999999, time.UTC), 1}, // just before cutoff
{time.Date(98, time.January, 2, 13, 5, 0, 0, time.UTC), 6}, {time.Date(1998, time.January, 1, 11, 59, 59, 999999999, time.UTC), 2}, //
{time.Date(98, time.January, 2, 16, 0, 0, 0, time.UTC), 1}, {time.Date(1998, time.January, 1, 12, 0, 0, 0, time.UTC), 3}, // equal to cutoff
{time.Date(98, time.January, 2, 16, 0, 0, 0, time.UTC), 3}, {time.Date(1998, time.January, 1, 12, 0, 0, 0, time.UTC), 4}, //
{time.Date(98, time.January, 2, 16, 0, 0, 0, time.UTC), 4}, {time.Date(1998, time.January, 1, 12, 0, 0, 1, time.UTC), 5}, // just after cutoff
{time.Date(98, time.January, 2, 16, 0, 0, 1, time.UTC), 0}, // TODO tidy up redundant entries {time.Date(1998, time.January, 1, 12, 0, 0, 1, time.UTC), 6}, //
{time.Date(9999, time.January, 1, 0, 0, 0, 0, time.UTC), 0}, // distant future
} }
cutoffTime := time.Date(98, time.January, 2, 16, 0, 0, 0, time.UTC) for _, v := range byTimeIndex {
var expectedQueue []types.ID
for _, i := range queue {
if i.endTime.After(cutoffTime) { // only append items where endTime ≤ cutoffTime
break
}
expectedQueue = append(expectedQueue, i.auctionID)
}
// write and read queue
for _, v := range queue {
keeper.InsertIntoQueue(ctx, v.endTime, v.auctionID) keeper.InsertIntoQueue(ctx, v.endTime, v.auctionID)
} }
var readQueue []types.ID
// read out values from index up to a cutoff time and check they are as expected
cutoffTime := time.Date(1998, time.January, 1, 12, 0, 0, 0, time.UTC)
var expectedIndex []types.ID
for _, v := range byTimeIndex {
if v.endTime.Before(cutoffTime) || v.endTime.Equal(cutoffTime) { // endTime ≤ cutoffTime
expectedIndex = append(expectedIndex, v.auctionID)
}
}
var readIndex []types.ID
keeper.IterateAuctionsByTime(ctx, cutoffTime, func(id types.ID) bool { keeper.IterateAuctionsByTime(ctx, cutoffTime, func(id types.ID) bool {
readQueue = append(readQueue, id) readIndex = append(readIndex, id)
return false return false
}) })
require.Equal(t, expectedQueue, readQueue) require.Equal(t, expectedIndex, readIndex)
} }
func convertIteratorToSlice(keeper keeper.Keeper, iterator sdk.Iterator) []types.ID { func convertIteratorToSlice(keeper keeper.Keeper, iterator sdk.Iterator) []types.ID {

View File

@ -13,7 +13,7 @@ const (
// DefaultMaxAuctionDuration max length of auction // DefaultMaxAuctionDuration max length of auction
DefaultMaxAuctionDuration time.Duration = 2 * 24 * time.Hour DefaultMaxAuctionDuration time.Duration = 2 * 24 * time.Hour
// DefaultBidDuration how long an auction gets extended when someone bids, roughly 3 hours in blocks // DefaultBidDuration how long an auction gets extended when someone bids, roughly 3 hours in blocks
DefaultMaxBidDuration time.Duration = 3 * time.Hour DefaultBidDuration time.Duration = 3 * time.Hour
) )
// Parameter keys // Parameter keys
@ -43,7 +43,7 @@ func NewAuctionParams(maxAuctionDuration time.Duration, bidDuration time.Duratio
func DefaultAuctionParams() AuctionParams { func DefaultAuctionParams() AuctionParams {
return NewAuctionParams( return NewAuctionParams(
DefaultMaxAuctionDuration, DefaultMaxAuctionDuration,
DefaultMaxBidDuration, DefaultBidDuration,
) )
} }