0g-chain/x/auction/keeper/store.go
2019-12-12 00:16:10 +00:00

188 lines
5.7 KiB
Go

package keeper
import (
"bytes"
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/auction/types"
)
// set an auction in the store, adding a new ID, and setting indexes
func (k Keeper) storeNewAuction(ctx sdk.Context, auction types.Auction) (types.ID, sdk.Error) {
// get ID
newAuctionID, err := k.getNextAuctionID(ctx)
if err != nil {
return 0, err
}
// set ID
auction.SetID(newAuctionID)
// store auction
k.SetAuction(ctx, auction)
k.incrementNextAuctionID(ctx)
return newAuctionID, nil
}
// getNextAuctionID gets the next available global AuctionID
func (k Keeper) getNextAuctionID(ctx sdk.Context) (types.ID, sdk.Error) {
// get next ID from store
store := ctx.KVStore(k.storeKey)
bz := store.Get(k.getNextAuctionIDKey())
if bz == nil {
// if not found, set the id at 0
bz = k.cdc.MustMarshalBinaryLengthPrefixed(types.ID(0))
store.Set(k.getNextAuctionIDKey(), bz)
// TODO Set auction ID in genesis
//return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
}
var auctionID types.ID
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &auctionID)
return auctionID, nil
}
// incrementNextAuctionID increments the global ID in the store by 1
func (k Keeper) incrementNextAuctionID(ctx sdk.Context) sdk.Error {
// get next ID from store
store := ctx.KVStore(k.storeKey)
bz := store.Get(k.getNextAuctionIDKey())
if bz == nil {
panic("initial auctionID never set in genesis")
//return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set") // TODO
}
var auctionID types.ID
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &auctionID)
// increment the stored next ID
bz = k.cdc.MustMarshalBinaryLengthPrefixed(auctionID + 1)
store.Set(k.getNextAuctionIDKey(), bz)
return nil
}
// SetAuction puts the auction into the database and adds it to the queue
// it overwrites any pre-existing auction with same ID
func (k Keeper) SetAuction(ctx sdk.Context, auction types.Auction) {
// remove the auction from the queue if it is already in there
existingAuction, found := k.GetAuction(ctx, auction.GetID())
if found {
k.removeFromQueue(ctx, existingAuction.GetEndTime(), existingAuction.GetID())
}
// store auction
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(auction)
store.Set(k.getAuctionKey(auction.GetID()), bz)
// add to the queue
k.InsertIntoQueue(ctx, auction.GetEndTime(), auction.GetID())
}
// getAuction gets an auction from the store by auctionID
func (k Keeper) GetAuction(ctx sdk.Context, auctionID types.ID) (types.Auction, bool) {
var auction types.Auction
store := ctx.KVStore(k.storeKey)
bz := store.Get(k.getAuctionKey(auctionID))
if bz == nil {
return auction, false
}
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &auction)
return auction, true
}
// DeleteAuction removes an auction from the store without any validation
func (k Keeper) DeleteAuction(ctx sdk.Context, auctionID types.ID) {
// remove from queue
auction, found := k.GetAuction(ctx, auctionID)
if found {
k.removeFromQueue(ctx, auction.GetEndTime(), auctionID)
}
// delete auction
store := ctx.KVStore(k.storeKey)
store.Delete(k.getAuctionKey(auctionID))
}
// ---------- Queue and key methods ----------
// These are lower level function used by the store methods above.
func (k Keeper) getNextAuctionIDKey() []byte {
return []byte("nextAuctionID")
}
func (k Keeper) getAuctionKey(auctionID types.ID) []byte {
return []byte(fmt.Sprintf("auctions:%d", auctionID))
}
// Inserts a AuctionID into the queue at endTime
func (k Keeper) InsertIntoQueue(ctx sdk.Context, endTime time.Time, auctionID types.ID) {
// get the store
store := ctx.KVStore(k.storeKey)
// marshal thing to be inserted
bz := k.cdc.MustMarshalBinaryLengthPrefixed(auctionID)
// store it
store.Set(
getQueueElementKey(endTime, auctionID),
bz,
)
}
// removes an auctionID from the queue
func (k Keeper) removeFromQueue(ctx sdk.Context, endTime time.Time, auctionID types.ID) {
store := ctx.KVStore(k.storeKey)
store.Delete(getQueueElementKey(endTime, auctionID))
}
// Returns an iterator for all the auctions in the queue that expire by endTime
func (k Keeper) GetQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { // TODO rename to "getAuctionsByExpiry" ?
// get store
store := ctx.KVStore(k.storeKey)
// get an interator
return store.Iterator(
queueKeyPrefix, // start key
sdk.PrefixEndBytes(getQueueElementKeyPrefix(endTime)), // end key (apparently exclusive but tests suggested otherwise)
)
}
// GetAuctionIterator returns an iterator over all auctions in the store
func (k Keeper) GetAuctionIterator(ctx sdk.Context) sdk.Iterator {
store := ctx.KVStore(k.storeKey)
return sdk.KVStorePrefixIterator(store, nil)
}
var queueKeyPrefix = []byte("queue")
var keyDelimiter = []byte(":")
// Returns half a key for an auctionID in the queue, it missed the id off the end
func getQueueElementKeyPrefix(endTime time.Time) []byte {
return bytes.Join([][]byte{
queueKeyPrefix,
sdk.Uint64ToBigEndian(uint64(endTime)), // TODO check this gives correct ordering
}, keyDelimiter)
}
// Returns the key for an auctionID in the queue
func getQueueElementKey(endTime time.Time, auctionID types.ID) []byte {
return bytes.Join([][]byte{
queueKeyPrefix,
sdk.Uint64ToBigEndian(uint64(endTime)), // TODO check this gives correct ordering
sdk.Uint64ToBigEndian(uint64(auctionID)),
}, keyDelimiter)
}
// GetAuctionID returns the id from an input Auction
func (k Keeper) DecodeAuctionID(ctx sdk.Context, idBytes []byte) types.ID {
var auctionID types.ID
k.cdc.MustUnmarshalBinaryLengthPrefixed(idBytes, &auctionID)
return auctionID
}
func (k Keeper) DecodeAuction(ctx sdk.Context, auctionBytes []byte) types.Auction {
var auction types.Auction
k.cdc.MustUnmarshalBinaryBare(auctionBytes, &auction)
return auction
}