From 5fa7309ca5abd4b76dd89c6c5b53fb980c0d0c98 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 17 May 2023 11:22:30 -0400 Subject: [PATCH] refactor: separate v1 and v2 (VE) (#142) --- abci/abci.go | 286 +++++++++ abci/abci_test.go | 635 +++++++++++++++++--- abci/v2/abci_test.go | 336 +++++++++++ abci/{ => v2}/auction_test.go | 2 +- abci/{auction.go => v2/proposal_auction.go} | 24 +- abci/{ => v2}/proposals.go | 5 +- abci/{ => v2}/proposals_test.go | 15 +- abci/{ => v2}/types.go | 4 +- abci/{ => v2}/vote_extensions.go | 2 +- abci/{ => v2}/vote_extensions_test.go | 48 +- go.mod | 5 + go.sum | 27 +- tests/e2e/e2e_test.go | 9 +- 13 files changed, 1229 insertions(+), 169 deletions(-) create mode 100644 abci/abci.go create mode 100644 abci/v2/abci_test.go rename abci/{ => v2}/auction_test.go (99%) rename abci/{auction.go => v2/proposal_auction.go} (92%) rename abci/{ => v2}/proposals.go (98%) rename abci/{ => v2}/proposals_test.go (96%) rename abci/{ => v2}/types.go (98%) rename abci/{ => v2}/vote_extensions.go (99%) rename abci/{ => v2}/vote_extensions_test.go (88%) diff --git a/abci/abci.go b/abci/abci.go new file mode 100644 index 0000000..af0c564 --- /dev/null +++ b/abci/abci.go @@ -0,0 +1,286 @@ +package abci + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" + "github.com/skip-mev/pob/mempool" +) + +type ( + Mempool interface { + sdkmempool.Mempool + + // The AuctionFactory interface is utilized to retrieve, validate, and wrap bid + // information into the block proposal. + mempool.AuctionFactory + + // AuctionBidSelect returns an iterator that iterates over the top bid + // transactions in the mempool. + AuctionBidSelect(ctx context.Context) sdkmempool.Iterator + } + + ProposalHandler struct { + mempool Mempool + logger log.Logger + anteHandler sdk.AnteHandler + txEncoder sdk.TxEncoder + txDecoder sdk.TxDecoder + } +) + +func NewProposalHandler( + mp Mempool, + logger log.Logger, + anteHandler sdk.AnteHandler, + txEncoder sdk.TxEncoder, + txDecoder sdk.TxDecoder, +) *ProposalHandler { + return &ProposalHandler{ + mempool: mp, + logger: logger, + anteHandler: anteHandler, + txEncoder: txEncoder, + txDecoder: txDecoder, + } +} + +// PrepareProposalHandler returns the PrepareProposal ABCI handler that performs +// top-of-block auctioning and general block proposal construction. +func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler { + return func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + var ( + selectedTxs [][]byte + totalTxBytes int64 + ) + + bidTxIterator := h.mempool.AuctionBidSelect(ctx) + txsToRemove := make(map[sdk.Tx]struct{}, 0) + seenTxs := make(map[string]struct{}, 0) + + // Attempt to select the highest bid transaction that is valid and whose + // bundled transactions are valid. + selectBidTxLoop: + for ; bidTxIterator != nil; bidTxIterator = bidTxIterator.Next() { + cacheCtx, write := ctx.CacheContext() + tmpBidTx := bidTxIterator.Tx() + + bidTxBz, err := h.PrepareProposalVerifyTx(cacheCtx, tmpBidTx) + if err != nil { + txsToRemove[tmpBidTx] = struct{}{} + continue selectBidTxLoop + } + + bidTxSize := int64(len(bidTxBz)) + if bidTxSize <= req.MaxTxBytes { + bidInfo, err := h.mempool.GetAuctionBidInfo(tmpBidTx) + if err != nil { + // Some transactions in the bundle may be malformatted or invalid, so + // we remove the bid transaction and try the next top bid. + txsToRemove[tmpBidTx] = struct{}{} + continue selectBidTxLoop + } + + // store the bytes of each ref tx as sdk.Tx bytes in order to build a valid proposal + bundledTransactions := bidInfo.Transactions + sdkTxBytes := make([][]byte, len(bundledTransactions)) + + // Ensure that the bundled transactions are valid + for index, rawRefTx := range bundledTransactions { + refTx, err := h.mempool.WrapBundleTransaction(rawRefTx) + if err != nil { + // Malformed bundled transaction, so we remove the bid transaction + // and try the next top bid. + txsToRemove[tmpBidTx] = struct{}{} + continue selectBidTxLoop + } + + txBz, err := h.PrepareProposalVerifyTx(cacheCtx, refTx) + if err != nil { + // Invalid bundled transaction, so we remove the bid transaction + // and try the next top bid. + txsToRemove[tmpBidTx] = struct{}{} + continue selectBidTxLoop + } + + sdkTxBytes[index] = txBz + } + + // At this point, both the bid transaction itself and all the bundled + // transactions are valid. So we select the bid transaction along with + // all the bundled transactions. We also mark these transactions as seen and + // update the total size selected thus far. + totalTxBytes += bidTxSize + selectedTxs = append(selectedTxs, bidTxBz) + selectedTxs = append(selectedTxs, sdkTxBytes...) + + for _, refTxRaw := range sdkTxBytes { + hash := sha256.Sum256(refTxRaw) + txHash := hex.EncodeToString(hash[:]) + seenTxs[txHash] = struct{}{} + } + + // Write the cache context to the original context when we know we have a + // valid top of block bundle. + write() + + break selectBidTxLoop + } + + txsToRemove[tmpBidTx] = struct{}{} + h.logger.Info( + "failed to select auction bid tx; tx size is too large", + "tx_size", bidTxSize, + "max_size", req.MaxTxBytes, + ) + } + + // Remove all invalid transactions from the mempool. + for tx := range txsToRemove { + h.RemoveTx(tx) + } + + iterator := h.mempool.Select(ctx, nil) + txsToRemove = map[sdk.Tx]struct{}{} + + // Select remaining transactions for the block proposal until we've reached + // size capacity. + selectTxLoop: + for ; iterator != nil; iterator = iterator.Next() { + memTx := iterator.Tx() + + // If the transaction is already included in the proposal, then we skip it. + txBz, err := h.txEncoder(memTx) + if err != nil { + txsToRemove[memTx] = struct{}{} + continue selectTxLoop + } + + hash := sha256.Sum256(txBz) + txHash := hex.EncodeToString(hash[:]) + if _, ok := seenTxs[txHash]; ok { + continue selectTxLoop + } + + txBz, err = h.PrepareProposalVerifyTx(ctx, memTx) + if err != nil { + txsToRemove[memTx] = struct{}{} + continue selectTxLoop + } + + txSize := int64(len(txBz)) + if totalTxBytes += txSize; totalTxBytes <= req.MaxTxBytes { + selectedTxs = append(selectedTxs, txBz) + } else { + // We've reached capacity per req.MaxTxBytes so we cannot select any + // more transactions. + break selectTxLoop + } + } + + // Remove all invalid transactions from the mempool. + for tx := range txsToRemove { + h.RemoveTx(tx) + } + + return abci.ResponsePrepareProposal{Txs: selectedTxs} + } +} + +// ProcessProposalHandler returns the ProcessProposal ABCI handler that performs +// block proposal verification. +func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler { + return func(ctx sdk.Context, req abci.RequestProcessProposal) abci.ResponseProcessProposal { + for index, txBz := range req.Txs { + tx, err := h.ProcessProposalVerifyTx(ctx, txBz) + if err != nil { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + + bidInfo, err := h.mempool.GetAuctionBidInfo(tx) + if err != nil { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + + // If the transaction is an auction bid, then we need to ensure that it is + // the first transaction in the block proposal and that the order of + // transactions in the block proposal follows the order of transactions in + // the bid. + if bidInfo != nil { + if index != 0 { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + + bundledTransactions := bidInfo.Transactions + if len(req.Txs) < len(bundledTransactions)+1 { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + + for i, refTxRaw := range bundledTransactions { + // Wrap and then encode the bundled transaction to ensure that the underlying + // reference transaction can be processed as an sdk.Tx. + wrappedTx, err := h.mempool.WrapBundleTransaction(refTxRaw) + if err != nil { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + + refTxBz, err := h.txEncoder(wrappedTx) + if err != nil { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + + if !bytes.Equal(refTxBz, req.Txs[i+1]) { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + } + } + + } + + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} + } +} + +// PrepareProposalVerifyTx encodes a transaction and verifies it. +func (h *ProposalHandler) PrepareProposalVerifyTx(ctx sdk.Context, tx sdk.Tx) ([]byte, error) { + txBz, err := h.txEncoder(tx) + if err != nil { + return nil, err + } + + return txBz, h.verifyTx(ctx, tx) +} + +// ProcessProposalVerifyTx decodes a transaction and verifies it. +func (h *ProposalHandler) ProcessProposalVerifyTx(ctx sdk.Context, txBz []byte) (sdk.Tx, error) { + tx, err := h.txDecoder(txBz) + if err != nil { + return nil, err + } + + return tx, h.verifyTx(ctx, tx) +} + +// VerifyTx verifies a transaction against the application's state. +func (h *ProposalHandler) verifyTx(ctx sdk.Context, tx sdk.Tx) error { + if h.anteHandler != nil { + _, err := h.anteHandler(ctx, tx, false) + return err + } + + return nil +} + +func (h *ProposalHandler) RemoveTx(tx sdk.Tx) { + if err := h.mempool.Remove(tx); err != nil && !errors.Is(err, sdkmempool.ErrTxNotFound) { + panic(fmt.Errorf("failed to remove invalid transaction from the mempool: %w", err)) + } +} diff --git a/abci/abci_test.go b/abci/abci_test.go index 28ae00d..df78c6f 100644 --- a/abci/abci_test.go +++ b/abci/abci_test.go @@ -1,11 +1,15 @@ package abci_test import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "fmt" "math/rand" "testing" "time" - comettypes "github.com/cometbft/cometbft/abci/types" + abcitypes "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/log" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" @@ -25,13 +29,12 @@ type ABCITestSuite struct { ctx sdk.Context // mempool setup - mempool *mempool.AuctionMempool - logger log.Logger - encodingConfig testutils.EncodingConfig - proposalHandler *abci.ProposalHandler - voteExtensionHandler *abci.VoteExtensionHandler - config mempool.AuctionFactory - txs map[string]struct{} + mempool *mempool.AuctionMempool + logger log.Logger + encodingConfig testutils.EncodingConfig + proposalHandler *abci.ProposalHandler + config mempool.AuctionFactory + txs map[string]struct{} // auction bid setup auctionBidAmount sdk.Coin @@ -97,7 +100,7 @@ func (suite *ABCITestSuite) SetupTest() { suite.builderDecorator = ante.NewBuilderDecorator(suite.builderKeeper, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.mempool) // Accounts set up - suite.accounts = testutils.RandomAccounts(suite.random, 10) + suite.accounts = testutils.RandomAccounts(suite.random, 1) suite.balances = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1000000000000000000))) suite.nonces = make(map[string]uint64) for _, acc := range suite.accounts { @@ -107,14 +110,13 @@ func (suite *ABCITestSuite) SetupTest() { // Proposal handler set up suite.logger = log.NewNopLogger() suite.proposalHandler = abci.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder()) - suite.voteExtensionHandler = abci.NewVoteExtensionHandler(suite.mempool, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.anteHandler) } -func (suite *ABCITestSuite) anteHandler(ctx sdk.Context, tx sdk.Tx, _ bool) (sdk.Context, error) { +func (suite *ABCITestSuite) anteHandler(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { signer := tx.GetMsgs()[0].GetSigners()[0] suite.bankKeeper.EXPECT().GetAllBalances(ctx, signer).AnyTimes().Return(suite.balances) - next := func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { return ctx, nil } @@ -123,12 +125,24 @@ func (suite *ABCITestSuite) anteHandler(ctx sdk.Context, tx sdk.Tx, _ bool) (sdk return ctx, err } + bz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx) + if err != nil { + return ctx, err + } + + if !simulate { + hash := sha256.Sum256(bz) + txHash := hex.EncodeToString(hash[:]) + if _, ok := suite.txs[txHash]; ok { + return ctx, fmt.Errorf("tx already in mempool") + } + suite.txs[txHash] = struct{}{} + } + return ctx, nil } func (suite *ABCITestSuite) createFilledMempool(numNormalTxs, numAuctionTxs, numBundledTxs int, insertRefTxs bool) int { - suite.mempool = mempool.NewAuctionMempool(suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), 0, suite.config) - // Insert a bunch of normal transactions into the global mempool for i := 0; i < numNormalTxs; i++ { // randomly select an account to create the tx @@ -212,10 +226,28 @@ func (suite *ABCITestSuite) createFilledMempool(numNormalTxs, numAuctionTxs, num return totalNumTxs } -func (suite *ABCITestSuite) exportMempool() [][]byte { +func (suite *ABCITestSuite) exportMempool(exportRefTxs bool) [][]byte { txs := make([][]byte, 0) seenTxs := make(map[string]bool) + auctionIterator := suite.mempool.AuctionBidSelect(suite.ctx) + for ; auctionIterator != nil; auctionIterator = auctionIterator.Next() { + auctionTx := auctionIterator.Tx() + txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(auctionTx) + suite.Require().NoError(err) + + txs = append(txs, txBz) + + if exportRefTxs { + for _, refRawTx := range auctionTx.GetMsgs()[0].(*buildertypes.MsgAuctionBid).GetTransactions() { + txs = append(txs, refRawTx) + seenTxs[string(refRawTx)] = true + } + } + + seenTxs[string(txBz)] = true + } + iterator := suite.mempool.Select(suite.ctx, nil) for ; iterator != nil; iterator = iterator.Next() { txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(iterator.Tx()) @@ -229,107 +261,510 @@ func (suite *ABCITestSuite) exportMempool() [][]byte { return txs } -func (suite *ABCITestSuite) createPrepareProposalRequest(maxBytes int64) comettypes.RequestPrepareProposal { - voteExtensions := make([]comettypes.ExtendedVoteInfo, 0) +func (suite *ABCITestSuite) TestPrepareProposal() { + var ( + // the modified transactions cannot exceed this size + maxTxBytes int64 = 1000000000000000000 - auctionIterator := suite.mempool.AuctionBidSelect(suite.ctx) - for ; auctionIterator != nil; auctionIterator = auctionIterator.Next() { - tx := auctionIterator.Tx() + // mempool configuration + numNormalTxs = 100 + numAuctionTxs = 100 + numBundledTxs = 3 + insertRefTxs = false - txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx) - suite.Require().NoError(err) + // auction configuration + maxBundleSize uint32 = 10 + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000)) + frontRunningProtection = true + ) - voteExtensions = append(voteExtensions, comettypes.ExtendedVoteInfo{ - VoteExtension: txBz, - }) - } - - return comettypes.RequestPrepareProposal{ - MaxTxBytes: maxBytes, - LocalLastCommit: comettypes.ExtendedCommitInfo{ - Votes: voteExtensions, + cases := []struct { + name string + malleate func() + expectedNumberProposalTxs int + expectedNumberTxsInMempool int + isTopBidValid bool + }{ + { + "single bundle in the mempool", + func() { + numNormalTxs = 0 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = true + }, + 4, + 3, + true, + }, + { + "single bundle in the mempool, no ref txs in mempool", + func() { + numNormalTxs = 0 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = false + }, + 4, + 0, + true, + }, + { + "single bundle in the mempool, not valid", + func() { + reserveFee = sdk.NewCoin("foo", sdk.NewInt(100000)) + suite.auctionBidAmount = sdk.NewCoin("foo", sdk.NewInt(10000)) // this will fail the ante handler + numNormalTxs = 0 + numAuctionTxs = 1 + numBundledTxs = 3 + }, + 0, + 0, + false, + }, + { + "single bundle in the mempool, not valid with ref txs in mempool", + func() { + reserveFee = sdk.NewCoin("foo", sdk.NewInt(100000)) + suite.auctionBidAmount = sdk.NewCoin("foo", sdk.NewInt(10000)) // this will fail the ante handler + numNormalTxs = 0 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = true + }, + 3, + 3, + false, + }, + { + "multiple bundles in the mempool, no normal txs + no ref txs in mempool", + func() { + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000)) + suite.auctionBidAmount = sdk.NewCoin("foo", sdk.NewInt(10000000)) + numNormalTxs = 0 + numAuctionTxs = 10 + numBundledTxs = 3 + insertRefTxs = false + }, + 4, + 0, + true, + }, + { + "multiple bundles in the mempool, no normal txs + ref txs in mempool", + func() { + numNormalTxs = 0 + numAuctionTxs = 10 + numBundledTxs = 3 + insertRefTxs = true + }, + 31, + 30, + true, + }, + { + "normal txs only", + func() { + numNormalTxs = 1 + numAuctionTxs = 0 + numBundledTxs = 0 + }, + 1, + 1, + false, + }, + { + "many normal txs only", + func() { + numNormalTxs = 100 + numAuctionTxs = 0 + numBundledTxs = 0 + }, + 100, + 100, + false, + }, + { + "single normal tx, single auction tx", + func() { + numNormalTxs = 1 + numAuctionTxs = 1 + numBundledTxs = 0 + }, + 2, + 1, + true, + }, + { + "single normal tx, single auction tx with ref txs", + func() { + numNormalTxs = 1 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = false + }, + 5, + 1, + true, + }, + { + "single normal tx, single failing auction tx with ref txs", + func() { + numNormalTxs = 1 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = true + suite.auctionBidAmount = sdk.NewCoin("foo", sdk.NewInt(2000)) // this will fail the ante handler + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000000000)) + }, + 4, + 4, + false, + }, + { + "many normal tx, single auction tx with no ref txs", + func() { + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000)) + suite.auctionBidAmount = sdk.NewCoin("foo", sdk.NewInt(2000000)) + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 0 + }, + 101, + 100, + true, + }, + { + "many normal tx, single auction tx with ref txs", + func() { + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = true + }, + 104, + 103, + true, + }, + { + "many normal tx, single auction tx with ref txs", + func() { + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = false + }, + 104, + 100, + true, + }, + { + "many normal tx, many auction tx with ref txs", + func() { + numNormalTxs = 100 + numAuctionTxs = 100 + numBundledTxs = 1 + insertRefTxs = true + }, + 201, + 200, + true, }, } -} -func (suite *ABCITestSuite) createExtendedCommitInfoFromTxBzs(txs [][]byte) []byte { - voteExtensions := make([]comettypes.ExtendedVoteInfo, 0) + for _, tc := range cases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.malleate() - for _, txBz := range txs { - voteExtensions = append(voteExtensions, comettypes.ExtendedVoteInfo{ - VoteExtension: txBz, + suite.createFilledMempool(numNormalTxs, numAuctionTxs, numBundledTxs, insertRefTxs) + + // create a new auction + params := buildertypes.Params{ + MaxBundleSize: maxBundleSize, + ReserveFee: reserveFee, + FrontRunningProtection: frontRunningProtection, + MinBidIncrement: suite.minBidIncrement, + } + suite.builderKeeper.SetParams(suite.ctx, params) + suite.builderDecorator = ante.NewBuilderDecorator(suite.builderKeeper, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.mempool) + + handler := suite.proposalHandler.PrepareProposalHandler() + res := handler(suite.ctx, abcitypes.RequestPrepareProposal{ + MaxTxBytes: maxTxBytes, + }) + + // -------------------- Check Invariants -------------------- // + // 1. The auction tx must fail if we know it is invalid + suite.Require().Equal(tc.isTopBidValid, suite.isTopBidValid()) + + // 2. total bytes must be less than or equal to maxTxBytes + totalBytes := int64(0) + if suite.isTopBidValid() { + totalBytes += int64(len(res.Txs[0])) + + for _, tx := range res.Txs[1+numBundledTxs:] { + totalBytes += int64(len(tx)) + } + } else { + for _, tx := range res.Txs { + totalBytes += int64(len(tx)) + } + } + suite.Require().LessOrEqual(totalBytes, maxTxBytes) + + // 3. the number of transactions in the response must be equal to the number of expected transactions + suite.Require().Equal(tc.expectedNumberProposalTxs, len(res.Txs)) + + // 4. if there are auction transactions, the first transaction must be the top bid + // and the rest of the bundle must be in the response + if suite.isTopBidValid() { + auctionTx, err := suite.encodingConfig.TxConfig.TxDecoder()(res.Txs[0]) + suite.Require().NoError(err) + + bidInfo, err := suite.mempool.GetAuctionBidInfo(auctionTx) + suite.Require().NoError(err) + + for index, tx := range bidInfo.Transactions { + suite.Require().Equal(tx, res.Txs[index+1]) + } + } + + // 5. All of the transactions must be unique + uniqueTxs := make(map[string]bool) + for _, tx := range res.Txs { + suite.Require().False(uniqueTxs[string(tx)]) + uniqueTxs[string(tx)] = true + } + + // 6. The number of transactions in the mempool must be correct + suite.Require().Equal(tc.expectedNumberTxsInMempool, suite.mempool.CountTx()) }) } - - commitInfo := comettypes.ExtendedCommitInfo{ - Votes: voteExtensions, - } - - commitInfoBz, err := commitInfo.Marshal() - suite.Require().NoError(err) - - return commitInfoBz } -func (suite *ABCITestSuite) createAuctionInfoFromTxBzs(txs [][]byte, numTxs uint64) []byte { - auctionInfo := abci.AuctionInfo{ - ExtendedCommitInfo: suite.createExtendedCommitInfoFromTxBzs(txs), - NumTxs: numTxs, - MaxTxBytes: int64(len(txs[0])), +func (suite *ABCITestSuite) TestProcessProposal() { + var ( + // mempool set up + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 3 + insertRefTxs = true + exportRefTxs = true + frontRunningTx sdk.Tx + + // auction set up + maxBundleSize uint32 = 10 + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000)) + frontRunningProtection = true + ) + + cases := []struct { + name string + malleate func() + isTopBidValid bool + response abcitypes.ResponseProcessProposal_ProposalStatus + }{ + { + "single normal tx, no auction tx", + func() { + numNormalTxs = 1 + numAuctionTxs = 0 + numBundledTxs = 0 + }, + false, + abcitypes.ResponseProcessProposal_ACCEPT, + }, + { + "single auction tx, no normal txs", + func() { + numNormalTxs = 0 + numAuctionTxs = 1 + numBundledTxs = 0 + }, + true, + abcitypes.ResponseProcessProposal_ACCEPT, + }, + { + "single auction tx, single auction tx", + func() { + numNormalTxs = 1 + numAuctionTxs = 1 + numBundledTxs = 0 + }, + true, + abcitypes.ResponseProcessProposal_ACCEPT, + }, + { + "single auction tx, single auction tx with ref txs", + func() { + numNormalTxs = 1 + numAuctionTxs = 1 + numBundledTxs = 4 + }, + true, + abcitypes.ResponseProcessProposal_ACCEPT, + }, + { + "single auction tx, single auction tx with no ref txs", + func() { + numNormalTxs = 1 + numAuctionTxs = 1 + numBundledTxs = 4 + insertRefTxs = false + exportRefTxs = false + }, + true, + abcitypes.ResponseProcessProposal_REJECT, + }, + { + "multiple auction txs, single normal tx", + func() { + numNormalTxs = 1 + numAuctionTxs = 2 + numBundledTxs = 4 + insertRefTxs = true + exportRefTxs = true + }, + true, + abcitypes.ResponseProcessProposal_REJECT, + }, + { + "single auction txs, multiple normal tx", + func() { + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 4 + }, + true, + abcitypes.ResponseProcessProposal_ACCEPT, + }, + { + "single invalid auction tx, multiple normal tx", + func() { + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 4 + reserveFee = sdk.NewCoin("foo", sdk.NewInt(100000000000000000)) + insertRefTxs = true + }, + false, + abcitypes.ResponseProcessProposal_REJECT, + }, + { + "single valid auction txs but missing ref txs", + func() { + numNormalTxs = 0 + numAuctionTxs = 1 + numBundledTxs = 4 + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000)) + insertRefTxs = false + exportRefTxs = false + }, + true, + abcitypes.ResponseProcessProposal_REJECT, + }, + { + "single valid auction txs but missing ref txs, with many normal txs", + func() { + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 4 + reserveFee = sdk.NewCoin("foo", sdk.NewInt(1000)) + insertRefTxs = false + exportRefTxs = false + }, + true, + abcitypes.ResponseProcessProposal_REJECT, + }, + { + "auction tx with frontrunning", + func() { + randomAccount := testutils.RandomAccounts(suite.random, 1)[0] + bidder := suite.accounts[0] + bid := sdk.NewCoin("foo", sdk.NewInt(696969696969)) + nonce := suite.nonces[bidder.Address.String()] + frontRunningTx, _ = testutils.CreateAuctionTxWithSigners(suite.encodingConfig.TxConfig, suite.accounts[0], bid, nonce+1, 1000, []testutils.Account{bidder, randomAccount}) + suite.Require().NotNil(frontRunningTx) + + numNormalTxs = 100 + numAuctionTxs = 1 + numBundledTxs = 4 + insertRefTxs = true + exportRefTxs = true + }, + false, + abcitypes.ResponseProcessProposal_REJECT, + }, + { + "auction tx with frontrunning, but frontrunning protection disabled", + func() { + randomAccount := testutils.RandomAccounts(suite.random, 1)[0] + bidder := suite.accounts[0] + bid := sdk.NewCoin("foo", sdk.NewInt(696969696969)) + nonce := suite.nonces[bidder.Address.String()] + frontRunningTx, _ = testutils.CreateAuctionTxWithSigners(suite.encodingConfig.TxConfig, suite.accounts[0], bid, nonce+1, 1000, []testutils.Account{bidder, randomAccount}) + suite.Require().NotNil(frontRunningTx) + + numAuctionTxs = 0 + frontRunningProtection = false + }, + true, + abcitypes.ResponseProcessProposal_ACCEPT, + }, } - auctionInfoBz, err := auctionInfo.Marshal() - suite.Require().NoError(err) + for _, tc := range cases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + tc.malleate() - return auctionInfoBz + suite.createFilledMempool(numNormalTxs, numAuctionTxs, numBundledTxs, insertRefTxs) + + if frontRunningTx != nil { + suite.Require().NoError(suite.mempool.Insert(suite.ctx, frontRunningTx)) + } + + // create a new auction + params := buildertypes.Params{ + MaxBundleSize: maxBundleSize, + ReserveFee: reserveFee, + FrontRunningProtection: frontRunningProtection, + MinBidIncrement: suite.minBidIncrement, + } + suite.builderKeeper.SetParams(suite.ctx, params) + suite.builderDecorator = ante.NewBuilderDecorator(suite.builderKeeper, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.mempool) + suite.Require().Equal(tc.isTopBidValid, suite.isTopBidValid()) + + txs := suite.exportMempool(exportRefTxs) + + if frontRunningTx != nil { + txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(frontRunningTx) + suite.Require().NoError(err) + + suite.Require().True(bytes.Equal(txs[0], txBz)) + } + + handler := suite.proposalHandler.ProcessProposalHandler() + res := handler(suite.ctx, abcitypes.RequestProcessProposal{ + Txs: txs, + }) + + // Check if the response is valid + suite.Require().Equal(tc.response, res.Status) + }) + } } -func (suite *ABCITestSuite) getAllAuctionTxs() ([]sdk.Tx, [][]byte) { - auctionIterator := suite.mempool.AuctionBidSelect(suite.ctx) - txs := make([]sdk.Tx, 0) - txBzs := make([][]byte, 0) - - for ; auctionIterator != nil; auctionIterator = auctionIterator.Next() { - txs = append(txs, auctionIterator.Tx()) - - bz, err := suite.encodingConfig.TxConfig.TxEncoder()(auctionIterator.Tx()) - suite.Require().NoError(err) - - txBzs = append(txBzs, bz) +// isTopBidValid returns true if the top bid is valid. We purposefully insert invalid +// auction transactions into the mempool to test the handlers. +func (suite *ABCITestSuite) isTopBidValid() bool { + iterator := suite.mempool.AuctionBidSelect(suite.ctx) + if iterator == nil { + return false } - return txs, txBzs -} - -func (suite *ABCITestSuite) createExtendedCommitInfoFromTxs(txs []sdk.Tx) comettypes.ExtendedCommitInfo { - voteExtensions := make([][]byte, 0) - for _, tx := range txs { - bz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx) - suite.Require().NoError(err) - - voteExtensions = append(voteExtensions, bz) - } - - return suite.createExtendedCommitInfo(voteExtensions) -} - -func (suite *ABCITestSuite) createExtendedVoteInfo(voteExtensions [][]byte) []comettypes.ExtendedVoteInfo { - commitInfo := make([]comettypes.ExtendedVoteInfo, 0) - for _, voteExtension := range voteExtensions { - info := comettypes.ExtendedVoteInfo{ - VoteExtension: voteExtension, - } - - commitInfo = append(commitInfo, info) - } - - return commitInfo -} - -func (suite *ABCITestSuite) createExtendedCommitInfo(voteExtensions [][]byte) comettypes.ExtendedCommitInfo { - commitInfo := comettypes.ExtendedCommitInfo{ - Votes: suite.createExtendedVoteInfo(voteExtensions), - } - - return commitInfo + // check if the top bid is valid + _, err := suite.anteHandler(suite.ctx, iterator.Tx(), true) + return err == nil } diff --git a/abci/v2/abci_test.go b/abci/v2/abci_test.go new file mode 100644 index 0000000..c1c3134 --- /dev/null +++ b/abci/v2/abci_test.go @@ -0,0 +1,336 @@ +package v2_test + +import ( + "math/rand" + "testing" + "time" + + comettypes "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/libs/log" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/mock/gomock" + "github.com/skip-mev/pob/abci" + v2 "github.com/skip-mev/pob/abci/v2" + "github.com/skip-mev/pob/mempool" + testutils "github.com/skip-mev/pob/testutils" + "github.com/skip-mev/pob/x/builder/ante" + "github.com/skip-mev/pob/x/builder/keeper" + buildertypes "github.com/skip-mev/pob/x/builder/types" + "github.com/stretchr/testify/suite" +) + +type ABCITestSuite struct { + suite.Suite + ctx sdk.Context + + // mempool setup + mempool *mempool.AuctionMempool + logger log.Logger + encodingConfig testutils.EncodingConfig + proposalHandler *v2.ProposalHandler + voteExtensionHandler *v2.VoteExtensionHandler + config mempool.AuctionFactory + txs map[string]struct{} + + // auction bid setup + auctionBidAmount sdk.Coin + minBidIncrement sdk.Coin + + // builder setup + builderKeeper keeper.Keeper + bankKeeper *testutils.MockBankKeeper + accountKeeper *testutils.MockAccountKeeper + distrKeeper *testutils.MockDistributionKeeper + stakingKeeper *testutils.MockStakingKeeper + builderDecorator ante.BuilderDecorator + key *storetypes.KVStoreKey + authorityAccount sdk.AccAddress + + // account set up + accounts []testutils.Account + balances sdk.Coins + random *rand.Rand + nonces map[string]uint64 +} + +func TestABCISuite(t *testing.T) { + suite.Run(t, new(ABCITestSuite)) +} + +func (suite *ABCITestSuite) SetupTest() { + // General config + suite.encodingConfig = testutils.CreateTestEncodingConfig() + 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.WithBlockHeight(1) + + // Mempool set up + suite.config = mempool.NewDefaultAuctionFactory(suite.encodingConfig.TxConfig.TxDecoder()) + suite.mempool = mempool.NewAuctionMempool(suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), 0, suite.config) + suite.txs = make(map[string]struct{}) + suite.auctionBidAmount = sdk.NewCoin("foo", sdk.NewInt(1000000000)) + suite.minBidIncrement = sdk.NewCoin("foo", sdk.NewInt(1000)) + + // Mock keepers set up + ctrl := gomock.NewController(suite.T()) + suite.accountKeeper = testutils.NewMockAccountKeeper(ctrl) + suite.accountKeeper.EXPECT().GetModuleAddress(buildertypes.ModuleName).Return(sdk.AccAddress{}).AnyTimes() + suite.bankKeeper = testutils.NewMockBankKeeper(ctrl) + suite.distrKeeper = testutils.NewMockDistributionKeeper(ctrl) + suite.stakingKeeper = testutils.NewMockStakingKeeper(ctrl) + suite.authorityAccount = sdk.AccAddress([]byte("authority")) + + // Builder keeper / decorator set up + suite.builderKeeper = keeper.NewKeeper( + suite.encodingConfig.Codec, + suite.key, + suite.accountKeeper, + suite.bankKeeper, + suite.distrKeeper, + suite.stakingKeeper, + suite.authorityAccount.String(), + ) + err := suite.builderKeeper.SetParams(suite.ctx, buildertypes.DefaultParams()) + suite.Require().NoError(err) + suite.builderDecorator = ante.NewBuilderDecorator(suite.builderKeeper, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.mempool) + + // Accounts set up + suite.accounts = testutils.RandomAccounts(suite.random, 10) + suite.balances = sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1000000000000000000))) + suite.nonces = make(map[string]uint64) + for _, acc := range suite.accounts { + suite.nonces[acc.Address.String()] = 0 + } + + // Proposal handler set up + suite.logger = log.NewNopLogger() + suite.proposalHandler = v2.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder()) + suite.voteExtensionHandler = v2.NewVoteExtensionHandler(suite.mempool, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.anteHandler) +} + +func (suite *ABCITestSuite) anteHandler(ctx sdk.Context, tx sdk.Tx, _ bool) (sdk.Context, error) { + signer := tx.GetMsgs()[0].GetSigners()[0] + suite.bankKeeper.EXPECT().GetAllBalances(ctx, signer).AnyTimes().Return(suite.balances) + + next := func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + } + + ctx, err := suite.builderDecorator.AnteHandle(ctx, tx, false, next) + if err != nil { + return ctx, err + } + + return ctx, nil +} + +func (suite *ABCITestSuite) createFilledMempool(numNormalTxs, numAuctionTxs, numBundledTxs int, insertRefTxs bool) int { + suite.mempool = mempool.NewAuctionMempool(suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), 0, suite.config) + + // Insert a bunch of normal transactions into the global mempool + for i := 0; i < numNormalTxs; i++ { + // randomly select an account to create the tx + randomIndex := suite.random.Intn(len(suite.accounts)) + acc := suite.accounts[randomIndex] + + // create a few random msgs + randomMsgs := testutils.CreateRandomMsgs(acc.Address, 3) + + nonce := suite.nonces[acc.Address.String()] + randomTx, err := testutils.CreateTx(suite.encodingConfig.TxConfig, acc, nonce, 1000, randomMsgs) + suite.Require().NoError(err) + + suite.nonces[acc.Address.String()]++ + priority := suite.random.Int63n(100) + 1 + suite.Require().NoError(suite.mempool.Insert(suite.ctx.WithPriority(priority), randomTx)) + } + + suite.Require().Equal(numNormalTxs, suite.mempool.CountTx()) + suite.Require().Equal(0, suite.mempool.CountAuctionTx()) + + // Insert a bunch of auction transactions into the global mempool and auction mempool + for i := 0; i < numAuctionTxs; i++ { + // randomly select a bidder to create the tx + randomIndex := suite.random.Intn(len(suite.accounts)) + acc := suite.accounts[randomIndex] + + // create a new auction bid msg with numBundledTxs bundled transactions + nonce := suite.nonces[acc.Address.String()] + bidMsg, err := testutils.CreateMsgAuctionBid(suite.encodingConfig.TxConfig, acc, suite.auctionBidAmount, nonce, numBundledTxs) + suite.nonces[acc.Address.String()] += uint64(numBundledTxs) + suite.Require().NoError(err) + + // create the auction tx + nonce = suite.nonces[acc.Address.String()] + auctionTx, err := testutils.CreateTx(suite.encodingConfig.TxConfig, acc, nonce, 1000, []sdk.Msg{bidMsg}) + suite.Require().NoError(err) + + // insert the auction tx into the global mempool + priority := suite.random.Int63n(100) + 1 + suite.Require().NoError(suite.mempool.Insert(suite.ctx.WithPriority(priority), auctionTx)) + suite.nonces[acc.Address.String()]++ + + if insertRefTxs { + for _, refRawTx := range bidMsg.GetTransactions() { + refTx, err := suite.encodingConfig.TxConfig.TxDecoder()(refRawTx) + suite.Require().NoError(err) + priority := suite.random.Int63n(100) + 1 + suite.Require().NoError(suite.mempool.Insert(suite.ctx.WithPriority(priority), refTx)) + } + } + + // decrement the bid amount for the next auction tx + suite.auctionBidAmount = suite.auctionBidAmount.Sub(suite.minBidIncrement) + } + + numSeenGlobalTxs := 0 + for iterator := suite.mempool.Select(suite.ctx, nil); iterator != nil; iterator = iterator.Next() { + numSeenGlobalTxs++ + } + + numSeenAuctionTxs := 0 + for iterator := suite.mempool.AuctionBidSelect(suite.ctx); iterator != nil; iterator = iterator.Next() { + numSeenAuctionTxs++ + } + + var totalNumTxs int + suite.Require().Equal(numAuctionTxs, suite.mempool.CountAuctionTx()) + if insertRefTxs { + totalNumTxs = numNormalTxs + numAuctionTxs*(numBundledTxs) + suite.Require().Equal(totalNumTxs, suite.mempool.CountTx()) + suite.Require().Equal(totalNumTxs, numSeenGlobalTxs) + } else { + totalNumTxs = numNormalTxs + suite.Require().Equal(totalNumTxs, suite.mempool.CountTx()) + suite.Require().Equal(totalNumTxs, numSeenGlobalTxs) + } + + suite.Require().Equal(numAuctionTxs, numSeenAuctionTxs) + + return totalNumTxs +} + +func (suite *ABCITestSuite) exportMempool() [][]byte { + txs := make([][]byte, 0) + seenTxs := make(map[string]bool) + + iterator := suite.mempool.Select(suite.ctx, nil) + for ; iterator != nil; iterator = iterator.Next() { + txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(iterator.Tx()) + suite.Require().NoError(err) + + if !seenTxs[string(txBz)] { + txs = append(txs, txBz) + } + } + + return txs +} + +func (suite *ABCITestSuite) createPrepareProposalRequest(maxBytes int64) comettypes.RequestPrepareProposal { + voteExtensions := make([]comettypes.ExtendedVoteInfo, 0) + + auctionIterator := suite.mempool.AuctionBidSelect(suite.ctx) + for ; auctionIterator != nil; auctionIterator = auctionIterator.Next() { + tx := auctionIterator.Tx() + + txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx) + suite.Require().NoError(err) + + voteExtensions = append(voteExtensions, comettypes.ExtendedVoteInfo{ + VoteExtension: txBz, + }) + } + + return comettypes.RequestPrepareProposal{ + MaxTxBytes: maxBytes, + LocalLastCommit: comettypes.ExtendedCommitInfo{ + Votes: voteExtensions, + }, + } +} + +func (suite *ABCITestSuite) createExtendedCommitInfoFromTxBzs(txs [][]byte) []byte { + voteExtensions := make([]comettypes.ExtendedVoteInfo, 0) + + for _, txBz := range txs { + voteExtensions = append(voteExtensions, comettypes.ExtendedVoteInfo{ + VoteExtension: txBz, + }) + } + + commitInfo := comettypes.ExtendedCommitInfo{ + Votes: voteExtensions, + } + + commitInfoBz, err := commitInfo.Marshal() + suite.Require().NoError(err) + + return commitInfoBz +} + +func (suite *ABCITestSuite) createAuctionInfoFromTxBzs(txs [][]byte, numTxs uint64) []byte { + auctionInfo := abci.AuctionInfo{ + ExtendedCommitInfo: suite.createExtendedCommitInfoFromTxBzs(txs), + NumTxs: numTxs, + MaxTxBytes: int64(len(txs[0])), + } + + auctionInfoBz, err := auctionInfo.Marshal() + suite.Require().NoError(err) + + return auctionInfoBz +} + +func (suite *ABCITestSuite) getAllAuctionTxs() ([]sdk.Tx, [][]byte) { + auctionIterator := suite.mempool.AuctionBidSelect(suite.ctx) + txs := make([]sdk.Tx, 0) + txBzs := make([][]byte, 0) + + for ; auctionIterator != nil; auctionIterator = auctionIterator.Next() { + txs = append(txs, auctionIterator.Tx()) + + bz, err := suite.encodingConfig.TxConfig.TxEncoder()(auctionIterator.Tx()) + suite.Require().NoError(err) + + txBzs = append(txBzs, bz) + } + + return txs, txBzs +} + +func (suite *ABCITestSuite) createExtendedCommitInfoFromTxs(txs []sdk.Tx) comettypes.ExtendedCommitInfo { + voteExtensions := make([][]byte, 0) + for _, tx := range txs { + bz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx) + suite.Require().NoError(err) + + voteExtensions = append(voteExtensions, bz) + } + + return suite.createExtendedCommitInfo(voteExtensions) +} + +func (suite *ABCITestSuite) createExtendedVoteInfo(voteExtensions [][]byte) []comettypes.ExtendedVoteInfo { + commitInfo := make([]comettypes.ExtendedVoteInfo, 0) + for _, voteExtension := range voteExtensions { + info := comettypes.ExtendedVoteInfo{ + VoteExtension: voteExtension, + } + + commitInfo = append(commitInfo, info) + } + + return commitInfo +} + +func (suite *ABCITestSuite) createExtendedCommitInfo(voteExtensions [][]byte) comettypes.ExtendedCommitInfo { + commitInfo := comettypes.ExtendedCommitInfo{ + Votes: suite.createExtendedVoteInfo(voteExtensions), + } + + return commitInfo +} diff --git a/abci/auction_test.go b/abci/v2/auction_test.go similarity index 99% rename from abci/auction_test.go rename to abci/v2/auction_test.go index 0609f57..cfeb487 100644 --- a/abci/auction_test.go +++ b/abci/v2/auction_test.go @@ -1,4 +1,4 @@ -package abci_test +package v2_test import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/abci/auction.go b/abci/v2/proposal_auction.go similarity index 92% rename from abci/auction.go rename to abci/v2/proposal_auction.go index 5aced5e..cd4a797 100644 --- a/abci/auction.go +++ b/abci/v2/proposal_auction.go @@ -1,4 +1,4 @@ -package abci +package v2 import ( "crypto/sha256" @@ -9,6 +9,7 @@ import ( abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" + pobabci "github.com/skip-mev/pob/abci" ) // TopOfBlock contains information about how the top of block should be built. @@ -30,8 +31,9 @@ func NewTopOfBlock() TopOfBlock { } } -// BuildTOB inputs all of the vote extensions and outputs a top of block proposal that includes -// the highest bidding valid transaction along with all the bundled transactions. +// BuildTOB inputs all of the vote extensions and outputs a top of block proposal +// that includes the highest bidding valid transaction along with all the bundled +// transactions. func (h *ProposalHandler) BuildTOB(ctx sdk.Context, voteExtensionInfo abci.ExtendedCommitInfo, maxBytes int64) TopOfBlock { // Get the bid transactions from the vote extensions. sortedBidTxs := h.GetBidsFromVoteExtensions(voteExtensionInfo.Votes) @@ -86,14 +88,14 @@ func (h *ProposalHandler) BuildTOB(ctx sdk.Context, voteExtensionInfo abci.Exten // VerifyTOB verifies that the set of vote extensions used in prepare proposal deterministically // produce the same top of block proposal. -func (h *ProposalHandler) VerifyTOB(ctx sdk.Context, proposalTxs [][]byte) (*AuctionInfo, error) { +func (h *ProposalHandler) VerifyTOB(ctx sdk.Context, proposalTxs [][]byte) (*pobabci.AuctionInfo, error) { // Proposal must include at least the auction info. if len(proposalTxs) < NumInjectedTxs { return nil, fmt.Errorf("proposal is too small; expected at least %d slots", NumInjectedTxs) } // Extract the auction info from the proposal. - auctionInfo := &AuctionInfo{} + auctionInfo := &pobabci.AuctionInfo{} if err := auctionInfo.Unmarshal(proposalTxs[AuctionInfoIndex]); err != nil { return nil, fmt.Errorf("failed to unmarshal auction info: %w", err) } @@ -103,7 +105,7 @@ func (h *ProposalHandler) VerifyTOB(ctx sdk.Context, proposalTxs [][]byte) (*Auc return nil, fmt.Errorf("number of txs in proposal do not match expected in auction info; expected at least %d slots", auctionInfo.NumTxs+NumInjectedTxs) } - // Unmarshall the vote extension information from the auction info. + // unmarshal the vote extension information from the auction info lastCommitInfo := abci.ExtendedCommitInfo{} if err := lastCommitInfo.Unmarshal(auctionInfo.ExtendedCommitInfo); err != nil { return nil, fmt.Errorf("failed to unmarshal last commit info from auction info: %w", err) @@ -155,9 +157,10 @@ func (h *ProposalHandler) GetBidsFromVoteExtensions(voteExtensions []abci.Extend return bidTxs } -// buildTOB verifies that the auction and bundled transactions are valid and returns the transactions that -// should be included in the top of block, size of the auction transaction and bundle, and a cache -// of all transactions that should be ignored. +// buildTOB verifies that the auction and bundled transactions are valid and +// returns the transactions that should be included in the top of block, size +// of the auction transaction and bundle, and a cache of all transactions that +// should be ignored. func (h *ProposalHandler) buildTOB(ctx sdk.Context, bidTx sdk.Tx) (TopOfBlock, error) { proposal := NewTopOfBlock() @@ -210,7 +213,8 @@ func (h *ProposalHandler) buildTOB(ctx sdk.Context, bidTx sdk.Tx) (TopOfBlock, e return proposal, nil } -// getAuctionTxFromVoteExtension extracts the auction transaction from the vote extension. +// getAuctionTxFromVoteExtension extracts the auction transaction from the vote +// extension. func (h *ProposalHandler) getAuctionTxFromVoteExtension(voteExtension []byte) (sdk.Tx, error) { if len(voteExtension) == 0 { return nil, fmt.Errorf("vote extension is empty") diff --git a/abci/proposals.go b/abci/v2/proposals.go similarity index 98% rename from abci/proposals.go rename to abci/v2/proposals.go index 18a1b4e..012a628 100644 --- a/abci/proposals.go +++ b/abci/v2/proposals.go @@ -1,4 +1,4 @@ -package abci +package v2 import ( "context" @@ -11,6 +11,7 @@ import ( "github.com/cometbft/cometbft/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool" + pobabci "github.com/skip-mev/pob/abci" mempool "github.com/skip-mev/pob/mempool" ) @@ -89,7 +90,7 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler { return abci.ResponsePrepareProposal{Txs: proposal} } - auctionInfo := AuctionInfo{ + auctionInfo := pobabci.AuctionInfo{ ExtendedCommitInfo: lastCommitInfo, MaxTxBytes: req.MaxTxBytes, NumTxs: uint64(len(topOfBlock.Txs)), diff --git a/abci/proposals_test.go b/abci/v2/proposals_test.go similarity index 96% rename from abci/proposals_test.go rename to abci/v2/proposals_test.go index ee046ba..e411230 100644 --- a/abci/proposals_test.go +++ b/abci/v2/proposals_test.go @@ -1,9 +1,10 @@ -package abci_test +package v2_test import ( comettypes "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/skip-mev/pob/abci" + v2 "github.com/skip-mev/pob/abci/v2" testutils "github.com/skip-mev/pob/testutils" "github.com/skip-mev/pob/x/builder/ante" buildertypes "github.com/skip-mev/pob/x/builder/types" @@ -298,7 +299,7 @@ func (suite *ABCITestSuite) TestPrepareProposal() { suite.builderDecorator = ante.NewBuilderDecorator(suite.builderKeeper, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.mempool) // Reset the proposal handler with the new mempool. - suite.proposalHandler = abci.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder()) + suite.proposalHandler = v2.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder()) // Create a prepare proposal request based on the current state of the mempool. handler := suite.proposalHandler.PrepareProposalHandler() @@ -308,12 +309,12 @@ func (suite *ABCITestSuite) TestPrepareProposal() { // -------------------- Check Invariants -------------------- // // The first slot in the proposal must be the auction info auctionInfo := abci.AuctionInfo{} - err := auctionInfo.Unmarshal(res.Txs[abci.AuctionInfoIndex]) + err := auctionInfo.Unmarshal(res.Txs[v2.AuctionInfoIndex]) suite.Require().NoError(err) // Total bytes must be less than or equal to maxTxBytes totalBytes := int64(0) - for _, tx := range res.Txs[abci.NumInjectedTxs:] { + for _, tx := range res.Txs[v2.NumInjectedTxs:] { totalBytes += int64(len(tx)) } suite.Require().LessOrEqual(totalBytes, maxTxBytes) @@ -331,13 +332,13 @@ func (suite *ABCITestSuite) TestPrepareProposal() { suite.Require().NoError(err) for index, tx := range bidInfo.Transactions { - suite.Require().Equal(tx, res.Txs[abci.NumInjectedTxs+index+1]) + suite.Require().Equal(tx, res.Txs[v2.NumInjectedTxs+index+1]) } } // 5. All of the transactions must be unique uniqueTxs := make(map[string]bool) - for _, tx := range res.Txs[abci.NumInjectedTxs:] { + for _, tx := range res.Txs[v2.NumInjectedTxs:] { suite.Require().False(uniqueTxs[string(tx)]) uniqueTxs[string(tx)] = true } @@ -751,7 +752,7 @@ func (suite *ABCITestSuite) TestProcessProposal() { suite.builderDecorator = ante.NewBuilderDecorator(suite.builderKeeper, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.mempool) // reset the proposal handler with the new mempool - suite.proposalHandler = abci.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder()) + suite.proposalHandler = v2.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder()) handler := suite.proposalHandler.ProcessProposalHandler() res := handler(suite.ctx, comettypes.RequestProcessProposal{ diff --git a/abci/types.go b/abci/v2/types.go similarity index 98% rename from abci/types.go rename to abci/v2/types.go index a9f18bb..169e71a 100644 --- a/abci/types.go +++ b/abci/v2/types.go @@ -1,10 +1,10 @@ /* -NOTE: These types are TEMPORARY and will be removed once the Cosmos SDK v0.38 +NOTE: These types are TEMPORARY and will be removed once the Cosmos SDK v0.48 alpha/RC tag is released. These types are simply used to prototype and develop against. */ //nolint -package abci +package v2 import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/abci/vote_extensions.go b/abci/v2/vote_extensions.go similarity index 99% rename from abci/vote_extensions.go rename to abci/v2/vote_extensions.go index bed1893..832ac24 100644 --- a/abci/vote_extensions.go +++ b/abci/v2/vote_extensions.go @@ -1,4 +1,4 @@ -package abci +package v2 import ( "context" diff --git a/abci/vote_extensions_test.go b/abci/v2/vote_extensions_test.go similarity index 88% rename from abci/vote_extensions_test.go rename to abci/v2/vote_extensions_test.go index 15c7621..87f9f04 100644 --- a/abci/vote_extensions_test.go +++ b/abci/v2/vote_extensions_test.go @@ -1,8 +1,8 @@ -package abci_test +package v2_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/skip-mev/pob/abci" + v2 "github.com/skip-mev/pob/abci/v2" "github.com/skip-mev/pob/mempool" testutils "github.com/skip-mev/pob/testutils" "github.com/skip-mev/pob/x/builder/types" @@ -132,7 +132,7 @@ func (suite *ABCITestSuite) TestExtendVoteExtensionHandler() { expectedVE := tc.getExpectedVE() // Reset the handler with the new mempool - suite.voteExtensionHandler = abci.NewVoteExtensionHandler(suite.mempool, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.anteHandler) + suite.voteExtensionHandler = v2.NewVoteExtensionHandler(suite.mempool, suite.encodingConfig.TxConfig.TxDecoder(), suite.encodingConfig.TxConfig.TxEncoder(), suite.anteHandler) handler := suite.voteExtensionHandler.ExtendVoteHandler() resp, err := handler(suite.ctx, nil) @@ -156,13 +156,13 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { testCases := []struct { name string - req func() *abci.RequestVerifyVoteExtension + req func() *v2.RequestVerifyVoteExtension expectedErr bool }{ { "invalid vote extension bytes", - func() *abci.RequestVerifyVoteExtension { - return &abci.RequestVerifyVoteExtension{ + func() *v2.RequestVerifyVoteExtension { + return &v2.RequestVerifyVoteExtension{ VoteExtension: []byte("invalid vote extension"), } }, @@ -170,8 +170,8 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "empty vote extension bytes", - func() *abci.RequestVerifyVoteExtension { - return &abci.RequestVerifyVoteExtension{ + func() *v2.RequestVerifyVoteExtension { + return &v2.RequestVerifyVoteExtension{ VoteExtension: []byte{}, } }, @@ -179,8 +179,8 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "nil vote extension bytes", - func() *abci.RequestVerifyVoteExtension { - return &abci.RequestVerifyVoteExtension{ + func() *v2.RequestVerifyVoteExtension { + return &v2.RequestVerifyVoteExtension{ VoteExtension: nil, } }, @@ -188,14 +188,14 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "invalid extension with bid tx with bad timeout", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { bidder := suite.accounts[0] bid := sdk.NewCoin("foo", sdk.NewInt(10)) signers := []testutils.Account{bidder} timeout := 0 bz := suite.createAuctionTxBz(bidder, bid, signers, timeout) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, @@ -203,14 +203,14 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "invalid vote extension with bid tx with bad bid", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { bidder := suite.accounts[0] bid := sdk.NewCoin("foo", sdk.NewInt(0)) signers := []testutils.Account{bidder} timeout := 10 bz := suite.createAuctionTxBz(bidder, bid, signers, timeout) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, @@ -218,14 +218,14 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "valid vote extension", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { bidder := suite.accounts[0] bid := params.ReserveFee signers := []testutils.Account{bidder} timeout := 10 bz := suite.createAuctionTxBz(bidder, bid, signers, timeout) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, @@ -233,7 +233,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "invalid vote extension with front running bid tx", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { bidder := suite.accounts[0] bid := params.ReserveFee timeout := 10 @@ -242,7 +242,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { signers := []testutils.Account{bidder, bundlee} bz := suite.createAuctionTxBz(bidder, bid, signers, timeout) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, @@ -250,7 +250,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "invalid vote extension with too many bundle txs", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { // disable front running protection params.FrontRunningProtection = false err := suite.builderKeeper.SetParams(suite.ctx, params) @@ -262,7 +262,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { timeout := 10 bz := suite.createAuctionTxBz(bidder, bid, signers, timeout) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, @@ -270,7 +270,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "invalid vote extension with a failing bundle tx", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { bidder := suite.accounts[0] bid := params.ReserveFee @@ -286,7 +286,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { bz, err := suite.encodingConfig.TxConfig.TxEncoder()(bidTx) suite.Require().NoError(err) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, @@ -294,7 +294,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { }, { "valid vote extension + no comparison to local mempool", - func() *abci.RequestVerifyVoteExtension { + func() *v2.RequestVerifyVoteExtension { bidder := suite.accounts[0] bid := params.ReserveFee signers := []testutils.Account{bidder} @@ -313,7 +313,7 @@ func (suite *ABCITestSuite) TestVerifyVoteExtensionHandler() { tx := suite.mempool.GetTopAuctionTx(suite.ctx) suite.Require().NotNil(tx) - return &abci.RequestVerifyVoteExtension{ + return &v2.RequestVerifyVoteExtension{ VoteExtension: bz, } }, diff --git a/go.mod b/go.mod index 760e84b..d835548 100644 --- a/go.mod +++ b/go.mod @@ -178,3 +178,8 @@ require ( pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +replace ( + github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 + github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 +) diff --git a/go.sum b/go.sum index 41eb9b9..9253eb0 100644 --- a/go.sum +++ b/go.sum @@ -205,8 +205,6 @@ filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= -github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= -github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -337,6 +335,8 @@ github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoK github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/iavl v0.20.0 h1:fTVznVlepH0KK8NyKq8w+U7c2L6jofa27aFX6YGlm38= github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= +github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= +github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/cosmos/ledger-cosmos-go v0.12.1 h1:sMBxza5p/rNK/06nBSNmsI/WDqI0pVJFVNihy1Y984w= github.com/cosmos/ledger-cosmos-go v0.12.1/go.mod h1:dhO6kj+Y+AHIOgAe4L9HL/6NDdyyth4q238I9yFpD2g= github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM= @@ -412,7 +412,6 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -445,7 +444,6 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= @@ -553,7 +551,6 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -777,22 +774,17 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -940,7 +932,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= @@ -948,8 +939,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= -github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg= @@ -1102,6 +1093,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1112,7 +1104,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1216,16 +1207,17 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1349,7 +1341,6 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index e450988..92a2ac5 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -12,13 +12,14 @@ func (s *IntegrationTestSuite) TestGetBuilderParams() { s.Require().NotNil(params) } -// TestBundles tests the execution of various auction bids. There are a few invarients that are -// tested: +// TestBundles tests the execution of various auction bids. There are a few +// invariants that are tested: +// // 1. The order of transactions in a bundle is preserved when bids are valid. // 2. All transactions execute as expected. // 3. The balance of the escrow account should be updated correctly. -// 4. Top of block bids will be included in block proposals before other transactions that are -// included in the same block. +// 4. Top of block bids will be included in block proposals before other transactions +// that are included in the same block. func (s *IntegrationTestSuite) TestBundles() { // Create the accounts that will create transactions to be included in bundles initBalance := sdk.NewInt64Coin(app.BondDenom, 10000000000)