fix(Config): Simplifying config interface (#104)

This commit is contained in:
David Terpay
2023-05-04 15:33:18 -04:00
committed by GitHub
parent 07c76b8330
commit d58b36bf3d
14 changed files with 345 additions and 564 deletions
+25 -85
View File
@@ -16,11 +16,8 @@ var _ sdk.AnteDecorator = BuilderDecorator{}
type (
Mempool interface {
Contains(tx sdk.Tx) (bool, error)
IsAuctionTx(tx sdk.Tx) (bool, error)
GetAuctionBidInfo(tx sdk.Tx) (mempool.AuctionBidInfo, error)
GetBundleSigners(txs [][]byte) ([]map[string]struct{}, error)
GetAuctionBidInfo(tx sdk.Tx) (*mempool.AuctionBidInfo, error)
GetTopAuctionTx(ctx context.Context) sdk.Tx
GetTimeout(tx sdk.Tx) (uint64, error)
}
BuilderDecorator struct {
@@ -55,108 +52,51 @@ func (ad BuilderDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
}
}
isAuctionTx, err := ad.mempool.IsAuctionTx(tx)
bidInfo, err := ad.mempool.GetAuctionBidInfo(tx)
if err != nil {
return ctx, err
}
// Validate the auction bid if one exists.
if isAuctionTx {
if bidInfo != nil {
// Auction transactions must have a timeout set to a valid block height.
if err := ad.HasValidTimeout(ctx, tx); err != nil {
return ctx, err
if int64(bidInfo.Timeout) < ctx.BlockHeight() {
return ctx, fmt.Errorf("timeout height cannot be less than the current block height")
}
bidInfo, err := ad.mempool.GetAuctionBidInfo(tx)
if err != nil {
return ctx, err
}
// If the current transaction is the highest bidding transaction, then the highest bid is empty.
topBid := sdk.Coin{}
// We only need to verify the auction bid relative to the local validator's mempool if the mode
// is checkTx or recheckTx. Otherwise, the ABCI handlers (VerifyVoteExtension, ExtendVoteExtension, etc.)
// will always compare the auction bid to the highest bidding transaction in the mempool leading to
// poor liveness guarantees.
topBid := sdk.Coin{}
if ctx.IsCheckTx() || ctx.IsReCheckTx() {
isTopBidTx, err := ad.IsTopBidTx(ctx, tx)
if err != nil {
return ctx, errors.Wrap(err, "failed to check if current transaction is highest bidding transaction")
}
if !isTopBidTx {
// Set the top bid to the highest bidding transaction.
topBid, err = ad.GetTopAuctionBid(ctx)
if topBidTx := ad.mempool.GetTopAuctionTx(ctx); topBidTx != nil {
topBidBz, err := ad.txEncoder(topBidTx)
if err != nil {
return ctx, errors.Wrap(err, "failed to get highest auction bid")
return ctx, err
}
currentTxBz, err := ad.txEncoder(tx)
if err != nil {
return ctx, err
}
// Compare the bytes to see if the current transaction is the highest bidding transaction.
if !bytes.Equal(topBidBz, currentTxBz) {
topBidInfo, err := ad.mempool.GetAuctionBidInfo(topBidTx)
if err != nil {
return ctx, err
}
topBid = topBidInfo.Bid
}
}
}
// Extract signers from bundle for verification.
signers, err := ad.mempool.GetBundleSigners(bidInfo.Transactions)
if err != nil {
return ctx, errors.Wrap(err, "failed to get bundle signers")
}
if err := ad.builderKeeper.ValidateBidInfo(ctx, topBid, bidInfo, signers); err != nil {
if err := ad.builderKeeper.ValidateBidInfo(ctx, topBid, bidInfo); err != nil {
return ctx, errors.Wrap(err, "failed to validate auction bid")
}
}
return next(ctx, tx, simulate)
}
// GetTopAuctionBid returns the highest auction bid if one exists.
func (ad BuilderDecorator) GetTopAuctionBid(ctx sdk.Context) (sdk.Coin, error) {
auctionTx := ad.mempool.GetTopAuctionTx(ctx)
if auctionTx == nil {
return sdk.Coin{}, nil
}
auctionBidInfo, err := ad.mempool.GetAuctionBidInfo(auctionTx)
if err != nil {
return sdk.Coin{}, err
}
return auctionBidInfo.Bid, nil
}
// IsTopBidTx returns true if the transaction inputted is the highest bidding auction transaction in the mempool.
func (ad BuilderDecorator) IsTopBidTx(ctx sdk.Context, tx sdk.Tx) (bool, error) {
auctionTx := ad.mempool.GetTopAuctionTx(ctx)
if auctionTx == nil {
return false, nil
}
topBidBz, err := ad.txEncoder(auctionTx)
if err != nil {
return false, err
}
currentTxBz, err := ad.txEncoder(tx)
if err != nil {
return false, err
}
return bytes.Equal(topBidBz, currentTxBz), nil
}
// HasValidTimeout returns true if the transaction has a valid timeout height.
func (ad BuilderDecorator) HasValidTimeout(ctx sdk.Context, tx sdk.Tx) error {
timeout, err := ad.mempool.GetTimeout(tx)
if err != nil {
return err
}
if timeout == 0 {
return fmt.Errorf("timeout height cannot be zero")
}
if timeout < uint64(ctx.BlockHeight()) {
return fmt.Errorf("timeout height cannot be less than the current block height")
}
return nil
}
+4 -3
View File
@@ -46,8 +46,7 @@ func (suite *AnteTestSuite) SetupTest() {
suite.random = rand.New(rand.NewSource(time.Now().Unix()))
suite.key = storetypes.NewKVStoreKey(buildertypes.StoreKey)
testCtx := testutil.DefaultContextWithDB(suite.T(), suite.key, storetypes.NewTransientStoreKey("transient_test"))
suite.ctx = testCtx.Ctx
suite.ctx = suite.ctx.WithIsCheckTx(true)
suite.ctx = testCtx.Ctx.WithIsCheckTx(true)
// Keepers set up
ctrl := gomock.NewController(suite.T())
@@ -234,6 +233,8 @@ func (suite *AnteTestSuite) TestAnteHandler() {
suite.SetupTest()
tc.malleate()
suite.ctx = suite.ctx.WithBlockHeight(1)
// Set the auction params
err := suite.builderKeeper.SetParams(suite.ctx, buildertypes.Params{
MaxBundleSize: maxBundleSize,
@@ -245,7 +246,7 @@ func (suite *AnteTestSuite) TestAnteHandler() {
suite.Require().NoError(err)
// Insert the top bid into the mempool
config := mempool.NewDefaultConfig(suite.encodingConfig.TxConfig.TxDecoder())
config := mempool.NewDefaultAuctionFactory(suite.encodingConfig.TxConfig.TxDecoder())
mempool := mempool.NewAuctionMempool(suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), 0, config)
if insertTopBid {
topAuctionTx, err := testutils.CreateAuctionTxWithSigners(suite.encodingConfig.TxConfig, topBidder, topBid, 0, timeout, []testutils.Account{})
+2 -2
View File
@@ -8,7 +8,7 @@ import (
)
// ValidateBidInfo validates that the bid can be included in the auction.
func (k Keeper) ValidateBidInfo(ctx sdk.Context, highestBid sdk.Coin, bidInfo mempool.AuctionBidInfo, signers []map[string]struct{}) error {
func (k Keeper) ValidateBidInfo(ctx sdk.Context, highestBid sdk.Coin, bidInfo *mempool.AuctionBidInfo) error {
// Validate the bundle size.
maxBundleSize, err := k.GetMaxBundleSize(ctx)
if err != nil {
@@ -31,7 +31,7 @@ func (k Keeper) ValidateBidInfo(ctx sdk.Context, highestBid sdk.Coin, bidInfo me
}
if protectionEnabled {
if err := k.ValidateAuctionBundle(bidInfo.Bidder, signers); err != nil {
if err := k.ValidateAuctionBundle(bidInfo.Bidder, bidInfo.Signers); err != nil {
return err
}
}
+20 -19
View File
@@ -11,7 +11,7 @@ import (
buildertypes "github.com/skip-mev/pob/x/builder/types"
)
func (suite *KeeperTestSuite) TestValidateAuctionMsg() {
func (suite *KeeperTestSuite) TestValidateBidInfo() {
var (
// Tx building variables
accounts = []testutils.Account{} // tracks the order of signers in the bundle
@@ -192,16 +192,23 @@ func (suite *KeeperTestSuite) TestValidateAuctionMsg() {
bundle = append(bundle, txBz)
}
bidInfo := mempool.AuctionBidInfo{
signers := make([]map[string]struct{}, len(accounts))
for index, acc := range accounts {
txSigners := map[string]struct{}{
acc.Address.String(): {},
}
signers[index] = txSigners
}
bidInfo := &mempool.AuctionBidInfo{
Bidder: bidder.Address,
Bid: bid,
Transactions: bundle,
Signers: signers,
}
signers, err := suite.mempool.GetBundleSigners(bundle)
suite.Require().NoError(err)
err = suite.builderKeeper.ValidateBidInfo(suite.ctx, highestBid, bidInfo, signers)
err := suite.builderKeeper.ValidateBidInfo(suite.ctx, highestBid, bidInfo)
if tc.pass {
suite.Require().NoError(err)
} else {
@@ -302,23 +309,17 @@ func (suite *KeeperTestSuite) TestValidateBundle() {
// Malleate the test case
tc.malleate()
// Create the bundle of transactions ordered by accounts
bundle := make([][]byte, 0)
for _, acc := range accounts {
// Create a random tx
tx, err := testutils.CreateRandomTx(suite.encCfg.TxConfig, acc, 0, 1, 1000)
suite.Require().NoError(err)
signers := make([]map[string]struct{}, len(accounts))
for index, acc := range accounts {
txSigners := map[string]struct{}{
acc.Address.String(): {},
}
txBz, err := suite.encCfg.TxConfig.TxEncoder()(tx)
suite.Require().NoError(err)
bundle = append(bundle, txBz)
signers[index] = txSigners
}
signers, err := suite.mempool.GetBundleSigners(bundle)
suite.Require().NoError(err)
// Validate the bundle
err = suite.builderKeeper.ValidateAuctionBundle(bidder.Address, signers)
err := suite.builderKeeper.ValidateAuctionBundle(bidder.Address, signers)
if tc.pass {
suite.Require().NoError(err)
} else {
+1 -1
View File
@@ -64,7 +64,7 @@ func (suite *KeeperTestSuite) SetupTest() {
err := suite.builderKeeper.SetParams(suite.ctx, types.DefaultParams())
suite.Require().NoError(err)
config := mempool.NewDefaultConfig(suite.encCfg.TxConfig.TxDecoder())
config := mempool.NewDefaultAuctionFactory(suite.encCfg.TxConfig.TxDecoder())
suite.mempool = mempool.NewAuctionMempool(suite.encCfg.TxConfig.TxDecoder(), suite.encCfg.TxConfig.TxEncoder(), 0, config)
suite.msgServer = keeper.NewMsgServerImpl(suite.builderKeeper)
}