[ENG-585]: Setting min bid increment in ante (#28)

This commit is contained in:
David Terpay 2023-03-16 19:40:09 -04:00 committed by GitHub
parent b6da342a49
commit fdfd12a81d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 11 deletions

View File

@ -158,6 +158,16 @@ func (am *AuctionMempool) RemoveWithoutRefTx(tx sdk.Tx) error {
return nil
}
// GetTopAuctionTx returns the highest bidding transaction in the auction mempool.
func (am *AuctionMempool) GetTopAuctionTx(ctx context.Context) sdk.Tx {
iterator := am.auctionIndex.Select(ctx, nil)
if iterator == nil {
return nil
}
return iterator.Tx()
}
// AuctionBidSelect returns an iterator over auction bids transactions only.
func (am *AuctionMempool) AuctionBidSelect(ctx context.Context) sdkmempool.Iterator {
return am.auctionIndex.Select(ctx, nil)

View File

@ -12,12 +12,14 @@ var _ sdk.AnteDecorator = AuctionDecorator{}
type AuctionDecorator struct {
auctionKeeper keeper.Keeper
txDecoder sdk.TxDecoder
mempool *mempool.AuctionMempool
}
func NewAuctionDecorator(ak keeper.Keeper, txDecoder sdk.TxDecoder) AuctionDecorator {
func NewAuctionDecorator(ak keeper.Keeper, txDecoder sdk.TxDecoder, mempool *mempool.AuctionMempool) AuctionDecorator {
return AuctionDecorator{
auctionKeeper: ak,
txDecoder: txDecoder,
mempool: mempool,
}
}
@ -46,10 +48,25 @@ func (ad AuctionDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
transactions[i] = decodedTx
}
if err := ad.auctionKeeper.ValidateAuctionMsg(ctx, bidder, auctionMsg.Bid, transactions); err != nil {
highestBid, err := ad.GetHighestAuctionBid(ctx)
if err != nil {
return ctx, errors.Wrap(err, "failed to get highest auction bid")
}
if err := ad.auctionKeeper.ValidateAuctionMsg(ctx, bidder, auctionMsg.Bid, highestBid, transactions); err != nil {
return ctx, errors.Wrap(err, "failed to validate auction bid")
}
}
return next(ctx, tx, simulate)
}
// GetHighestAuctionBid returns the highest auction bid if one exists.
func (ad AuctionDecorator) GetHighestAuctionBid(ctx sdk.Context) (sdk.Coins, error) {
auctionTx := ad.mempool.GetTopAuctionTx(ctx)
if auctionTx == nil {
return sdk.NewCoins(), nil
}
return auctionTx.(*mempool.WrappedBidTx).GetBid(), nil
}

View File

@ -6,10 +6,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// ValidateAuctionMsg validates that the MsgAuctionBid is valid. It checks that the bidder has sufficient funds to bid the
// amount specified in the message, that the bundle size is not greater than the max bundle size, and that the bundle
// transactions are valid.
func (k Keeper) ValidateAuctionMsg(ctx sdk.Context, bidder sdk.AccAddress, bid sdk.Coins, transactions []sdk.Tx) error {
// ValidateAuctionMsg validates that the MsgAuctionBid can be included in the auction.
func (k Keeper) ValidateAuctionMsg(ctx sdk.Context, bidder sdk.AccAddress, bid, highestBid sdk.Coins, transactions []sdk.Tx) error {
// Validate the bundle size.
maxBundleSize, err := k.GetMaxBundleSize(ctx)
if err != nil {
@ -21,7 +19,7 @@ func (k Keeper) ValidateAuctionMsg(ctx sdk.Context, bidder sdk.AccAddress, bid s
}
// Validate the bid amount.
if err := k.ValidateAuctionBid(ctx, bidder, bid); err != nil {
if err := k.ValidateAuctionBid(ctx, bidder, bid, highestBid); err != nil {
return err
}
@ -40,8 +38,20 @@ func (k Keeper) ValidateAuctionMsg(ctx sdk.Context, bidder sdk.AccAddress, bid s
return nil
}
// ValidateAuctionBid validates that the bidder has sufficient funds to participate in the auction.
func (k Keeper) ValidateAuctionBid(ctx sdk.Context, bidder sdk.AccAddress, bid sdk.Coins) error {
// ValidateAuctionBid validates that the bidder has sufficient funds to participate in the auction and that the bid amount
// is sufficiently high enough.
func (k Keeper) ValidateAuctionBid(ctx sdk.Context, bidder sdk.AccAddress, bid, highestBid sdk.Coins) error {
// Ensure the bid is greater than the highest bid + min bid increment.
minBidIncrement, err := k.GetMinBidIncrement(ctx)
if err != nil {
return err
}
minBid := highestBid.Add(minBidIncrement...)
if !bid.IsAllGTE(minBid) {
return fmt.Errorf("bid amount (%s) is less than the highest bid (%s) + min bid increment (%s)", bid, highestBid, minBidIncrement)
}
// Get the bid floor.
reserveFee, err := k.GetReserveFee(ctx)
if err != nil {

View File

@ -24,8 +24,12 @@ func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
maxBundleSize uint32 = 10
reserveFee = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1000)))
minBuyInFee = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1000)))
minBidIncrement = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1000)))
escrowAddress = sdk.AccAddress([]byte("escrow"))
frontRunningProtection = true
// mempool variables
highestBid = sdk.NewCoins()
)
rnd := rand.New(rand.NewSource(time.Now().Unix()))
@ -123,6 +127,23 @@ func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
},
true,
},
{
"invalid bundle that does not outbid the highest bid",
func() {
accounts = []Account{bidder, bidder, bidder}
highestBid = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(500)))
bid = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(500)))
},
false,
},
{
"valid bundle that outbids the highest bid",
func() {
highestBid = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(500)))
bid = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1500)))
},
true,
},
}
for _, tc := range cases {
@ -148,6 +169,7 @@ func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
MinBuyInFee: minBuyInFee,
EscrowAccountAddress: escrowAddress.String(),
FrontRunningProtection: frontRunningProtection,
MinBidIncrement: minBidIncrement,
}
suite.auctionKeeper.SetParams(suite.ctx, params)
@ -159,7 +181,7 @@ func (suite *IntegrationTestSuite) TestValidateAuctionMsg() {
bundle = append(bundle, tx)
}
err := suite.auctionKeeper.ValidateAuctionMsg(suite.ctx, bidder.Address, bid, bundle)
err := suite.auctionKeeper.ValidateAuctionMsg(suite.ctx, bidder.Address, bid, highestBid, bundle)
if tc.pass {
suite.Require().NoError(err)
} else {

View File

@ -18,6 +18,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/golang/mock/gomock"
"github.com/skip-mev/pob/mempool"
"github.com/skip-mev/pob/x/auction/ante"
"github.com/skip-mev/pob/x/auction/keeper"
"github.com/skip-mev/pob/x/auction/types"
@ -37,6 +38,8 @@ type IntegrationTestSuite struct {
msgServer types.MsgServer
key *storetypes.KVStoreKey
authorityAccount sdk.AccAddress
mempool *mempool.AuctionMempool
}
func TestKeeperTestSuite(t *testing.T) {
@ -60,7 +63,8 @@ func (suite *IntegrationTestSuite) SetupTest() {
err := suite.auctionKeeper.SetParams(suite.ctx, types.DefaultParams())
suite.Require().NoError(err)
suite.AuctionDecorator = ante.NewAuctionDecorator(suite.auctionKeeper, suite.encCfg.TxConfig.TxDecoder())
suite.mempool = mempool.NewAuctionMempool(suite.encCfg.TxConfig.TxDecoder(), 0)
suite.AuctionDecorator = ante.NewAuctionDecorator(suite.auctionKeeper, suite.encCfg.TxConfig.TxDecoder(), suite.mempool)
suite.msgServer = keeper.NewMsgServerImpl(suite.auctionKeeper)
}