refactor: separate v1 and v2 (VE) (#142)

This commit is contained in:
Aleksandr Bezobchuk 2023-05-17 11:22:30 -04:00 committed by GitHub
parent 0e5519baee
commit 5fa7309ca5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1229 additions and 169 deletions

286
abci/abci.go Normal file
View File

@ -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))
}
}

View File

@ -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
}

336
abci/v2/abci_test.go Normal file
View File

@ -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
}

View File

@ -1,4 +1,4 @@
package abci_test
package v2_test
import (
sdk "github.com/cosmos/cosmos-sdk/types"

View File

@ -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")

View File

@ -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)),

View File

@ -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{

View File

@ -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"

View File

@ -1,4 +1,4 @@
package abci
package v2
import (
"context"

View File

@ -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,
}
},

5
go.mod
View File

@ -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
)

27
go.sum
View File

@ -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=

View File

@ -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)