feat(adapters): Add SignerExtractionAdapter [ENG-1916] (#114)

* add a signer-extraction-adapter

* linting

* feat(adapters/mev-lane):  Use the SignerExtractionAdapter in the Mev-Lane [ENG-1917] (#115)

* use SignerExtractionAdapter in the Factory

* feat(e2e): block sdk integration updates (#122)

* cherry-pick from injective

* remove transactions from app-side mempool on failed re-checktx
This commit is contained in:
Nikhil Vasan 2023-09-27 08:08:10 -07:00 committed by GitHub
parent 3e5fce9a54
commit 3abfde4f34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 675 additions and 300 deletions

View File

@ -119,7 +119,7 @@ TEST_INTEGRATION_TAGS = integration
test-integration: $(TEST_INTEGRATION_DEPS)
@ echo "Running integration tests..."
@go test ./tests/integration/block_sdk_integration_test.go -timeout 30m -race -v -tags='$(TEST_INTEGRATION_TAGS)'
@go test ./tests/integration/block_sdk_integration_test.go -timeout 30m -p 1 -race -v -tags='$(TEST_INTEGRATION_TAGS)'
test: use-main
@go test -v -race $(shell go list ./... | grep -v tests/)

View File

@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/suite"
"github.com/skip-mev/block-sdk/abci"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
defaultlane "github.com/skip-mev/block-sdk/lanes/base"
@ -735,11 +736,12 @@ func (s *ProposalsTestSuite) setUpAnteHandler(expectedExecution map[sdk.Tx]bool)
func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *defaultlane.DefaultLane {
cfg := base.LaneConfig{
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
}
return defaultlane.NewDefaultLane(cfg)
@ -747,23 +749,25 @@ func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, exp
func (s *ProposalsTestSuite) setUpTOBLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *mev.MEVLane {
cfg := base.LaneConfig{
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: maxBlockSpace,
}
return mev.NewMEVLane(cfg, mev.NewDefaultAuctionFactory(cfg.TxDecoder))
return mev.NewMEVLane(cfg, mev.NewDefaultAuctionFactory(cfg.TxDecoder, signer_extraction.NewDefaultAdapter()))
}
func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *free.FreeLane {
cfg := base.LaneConfig{
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: s.setUpAnteHandler(expectedExecution),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: maxBlockSpace,
}
return free.NewFreeLane(cfg, base.DefaultTxPriority(), free.DefaultMatchHandler())
@ -771,16 +775,17 @@ func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expecte
func (s *ProposalsTestSuite) setUpPanicLane(maxBlockSpace math.LegacyDec) *base.BaseLane {
cfg := base.LaneConfig{
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
MaxBlockSpace: maxBlockSpace,
Logger: log.NewTestLogger(s.T()),
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: maxBlockSpace,
}
lane := base.NewBaseLane(
cfg,
"panic",
base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, 0),
base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, signer_extraction.NewDefaultAdapter(), 0),
base.DefaultMatchHandler(),
)

View File

@ -0,0 +1,51 @@
package signerextraction
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
)
type SignerData struct {
Signer sdk.AccAddress
Sequence uint64
}
// SignerExtractionAdapter is an interface used to determine how the signers of a transaction should be extracted
// from the transaction.
type Adapter interface {
GetSigners(sdk.Tx) ([]SignerData, error)
}
var _ Adapter = DefaultAdapter{}
// DefaultSignerExtractionAdapter is the default implementation of SignerExtractionAdapter. It extracts the signers
// from a cosmos-sdk tx via GetSignaturesV2.
type DefaultAdapter struct{}
func NewDefaultAdapter() DefaultAdapter {
return DefaultAdapter{}
}
func (DefaultAdapter) GetSigners(tx sdk.Tx) ([]SignerData, error) {
sigTx, ok := tx.(signing.SigVerifiableTx)
if !ok {
return nil, fmt.Errorf("tx of type %T does not implement SigVerifiableTx", tx)
}
sigs, err := sigTx.GetSignaturesV2()
if err != nil {
return nil, err
}
signers := make([]SignerData, len(sigs))
for i, sig := range sigs {
signers[i] = SignerData{
Signer: sig.PubKey.Address().Bytes(),
Sequence: sig.Sequence,
}
}
return signers, nil
}

View File

@ -0,0 +1,53 @@
package signerextraction_test
import (
"math/rand"
"testing"
"cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
testutils "github.com/skip-mev/block-sdk/testutils"
"github.com/stretchr/testify/suite"
)
type SignerExtractionAdapterTestSuite struct {
suite.Suite
txConfig client.TxConfig
accts []testutils.Account
adapter signer_extraction.DefaultAdapter
}
func TestSignerExtractionAdapterTestSuite(t *testing.T) {
suite.Run(t, new(SignerExtractionAdapterTestSuite))
}
func (s *SignerExtractionAdapterTestSuite) SetupTest() {
encodingConfig := testutils.CreateTestEncodingConfig()
s.txConfig = encodingConfig.TxConfig
accts := testutils.RandomAccounts(rand.New(rand.NewSource(1)), 2)
s.accts = accts
}
func (s *SignerExtractionAdapterTestSuite) TestGetSigners() {
acct := s.accts[0]
tx, err := testutils.CreateTx(s.txConfig, acct, 1, 1, []sdk.Msg{
&banktypes.MsgSend{
FromAddress: acct.Address.String(),
ToAddress: acct.Address.String(),
Amount: sdk.NewCoins(sdk.NewInt64Coin("test", 1)),
},
}, sdk.NewCoins(sdk.NewCoin("test", math.NewInt(1)))...)
s.Require().NoError(err)
signers, err := s.adapter.GetSigners(tx)
s.Require().NoError(err)
s.Require().Len(signers, 1)
s.Require().Equal(acct.Address.String(), signers[0].Signer.String())
s.Require().Equal(uint64(1), signers[0].Sequence)
}

View File

@ -7,6 +7,7 @@ import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
)
@ -17,6 +18,10 @@ type LaneConfig struct {
TxDecoder sdk.TxDecoder
AnteHandler sdk.AnteHandler
// SignerExtractor defines the interface used for extracting the expected signers of a transaction
// from the transaction.
SignerExtractor signer_extraction.Adapter
// MaxBlockSpace defines the relative percentage of block space that can be
// used by this lane. NOTE: If this is set to zero, then there is no limit
// on the number of transactions that can be included in the block for this
@ -47,14 +52,16 @@ func NewLaneConfig(
txEncoder sdk.TxEncoder,
txDecoder sdk.TxDecoder,
anteHandler sdk.AnteHandler,
signerExtractor signer_extraction.Adapter,
maxBlockSpace math.LegacyDec,
) LaneConfig {
return LaneConfig{
Logger: logger,
TxEncoder: txEncoder,
TxDecoder: txDecoder,
AnteHandler: anteHandler,
MaxBlockSpace: maxBlockSpace,
Logger: logger,
TxEncoder: txEncoder,
TxDecoder: txDecoder,
AnteHandler: anteHandler,
MaxBlockSpace: maxBlockSpace,
SignerExtractor: signerExtractor,
}
}
@ -72,6 +79,10 @@ func (c *LaneConfig) ValidateBasic() error {
return fmt.Errorf("tx decoder cannot be nil")
}
if c.SignerExtractor == nil {
return fmt.Errorf("signer extractor cannot be nil")
}
if c.MaxBlockSpace.IsNil() || c.MaxBlockSpace.IsNegative() || c.MaxBlockSpace.GT(math.LegacyOneDec()) {
return fmt.Errorf("max block space must be set to a value between 0 and 1")
}

View File

@ -8,6 +8,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block/utils"
)
@ -81,13 +82,14 @@ func DefaultTxPriority() TxPriority[string] {
}
// NewMempool returns a new Mempool.
func NewMempool[C comparable](txPriority TxPriority[C], txEncoder sdk.TxEncoder, maxTx int) *Mempool[C] {
func NewMempool[C comparable](txPriority TxPriority[C], txEncoder sdk.TxEncoder, extractor signer_extraction.Adapter, maxTx int) *Mempool[C] {
return &Mempool[C]{
index: NewPriorityMempool(
PriorityNonceMempoolConfig[C]{
TxPriority: txPriority,
MaxTx: maxTx,
},
extractor,
),
txPriority: txPriority,
txEncoder: txEncoder,

View File

@ -21,7 +21,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
)
var (
@ -62,11 +62,12 @@ type (
// priority to other sender txs and must be partially ordered by both sender-nonce
// and priority.
PriorityNonceMempool[C comparable] struct {
priorityIndex *skiplist.SkipList
priorityCounts map[C]int
senderIndices map[string]*skiplist.SkipList
scores map[txMeta[C]]txMeta[C]
cfg PriorityNonceMempoolConfig[C]
priorityIndex *skiplist.SkipList
priorityCounts map[C]int
senderIndices map[string]*skiplist.SkipList
scores map[txMeta[C]]txMeta[C]
cfg PriorityNonceMempoolConfig[C]
signerExtractor signer_extraction.Adapter
}
// PriorityNonceIterator defines an iterator that is used for mempool iteration
@ -167,21 +168,22 @@ func skiplistComparable[C comparable](txPriority TxPriority[C]) skiplist.Compara
// NewPriorityMempool returns the SDK's default mempool implementation which
// returns txs in a partial order by 2 dimensions; priority, and sender-nonce.
func NewPriorityMempool[C comparable](cfg PriorityNonceMempoolConfig[C]) *PriorityNonceMempool[C] {
func NewPriorityMempool[C comparable](cfg PriorityNonceMempoolConfig[C], extractor signer_extraction.Adapter) *PriorityNonceMempool[C] {
mp := &PriorityNonceMempool[C]{
priorityIndex: skiplist.New(skiplistComparable(cfg.TxPriority)),
priorityCounts: make(map[C]int),
senderIndices: make(map[string]*skiplist.SkipList),
scores: make(map[txMeta[C]]txMeta[C]),
cfg: cfg,
priorityIndex: skiplist.New(skiplistComparable(cfg.TxPriority)),
priorityCounts: make(map[C]int),
senderIndices: make(map[string]*skiplist.SkipList),
scores: make(map[txMeta[C]]txMeta[C]),
cfg: cfg,
signerExtractor: extractor,
}
return mp
}
// DefaultPriorityMempool returns a priorityNonceMempool with no options.
func DefaultPriorityMempool() *PriorityNonceMempool[int64] {
return NewPriorityMempool(DefaultPriorityNonceMempoolConfig())
func DefaultPriorityMempool(extractor signer_extraction.DefaultAdapter) *PriorityNonceMempool[int64] {
return NewPriorityMempool(DefaultPriorityNonceMempoolConfig(), extractor)
}
// NextSenderTx returns the next transaction for a given sender by nonce order,
@ -213,18 +215,18 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error
return nil
}
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
signers, err := mp.signerExtractor.GetSigners(tx)
if err != nil {
return err
}
if len(sigs) == 0 {
if len(signers) == 0 {
return fmt.Errorf("tx must have at least one signer")
}
sig := sigs[0]
sender := sdk.AccAddress(sig.PubKey.Address()).String()
signer := signers[0]
sender := signer.Signer.String()
priority := mp.cfg.TxPriority.GetTxPriority(ctx, tx)
nonce := sig.Sequence
nonce := signer.Sequence
key := txMeta[C]{nonce: nonce, priority: priority, sender: sender}
senderIndex, ok := mp.senderIndices[sender]
@ -427,16 +429,16 @@ func (mp *PriorityNonceMempool[C]) CountTx() int {
// Remove removes a transaction from the mempool in O(log n) time, returning an
// error if unsuccessful.
func (mp *PriorityNonceMempool[C]) Remove(tx sdk.Tx) error {
sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2()
signers, err := mp.signerExtractor.GetSigners(tx)
if err != nil {
return err
}
if len(sigs) == 0 {
if len(signers) == 0 {
return fmt.Errorf("attempted to remove a tx with no signatures")
}
sig := sigs[0]
sender := sdk.AccAddress(sig.PubKey.Address()).String()
sig := signers[0]
sender := sig.Signer.String()
nonce := sig.Sequence
scoreKey := txMeta[C]{nonce: nonce, sender: sender}

View File

@ -12,6 +12,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
defaultlane "github.com/skip-mev/block-sdk/lanes/base"
@ -60,24 +61,26 @@ func (suite *BlockBusterTestSuite) SetupTest() {
// TOB lane set up
suite.gasTokenDenom = "stake"
mevConfig := base.LaneConfig{
Logger: log.NewNopLogger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
Logger: log.NewNopLogger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
}
suite.mevLane = mev.NewMEVLane(
mevConfig,
mev.NewDefaultAuctionFactory(suite.encodingConfig.TxConfig.TxDecoder()),
mev.NewDefaultAuctionFactory(suite.encodingConfig.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()),
)
// Free lane set up
freeConfig := base.LaneConfig{
Logger: log.NewNopLogger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
Logger: log.NewNopLogger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
}
suite.freeLane = free.NewFreeLane(
freeConfig,
@ -87,11 +90,12 @@ func (suite *BlockBusterTestSuite) SetupTest() {
// Base lane set up
baseConfig := base.LaneConfig{
Logger: log.NewNopLogger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
Logger: log.NewNopLogger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
}
suite.baseLane = defaultlane.NewDefaultLane(
baseConfig,

View File

@ -9,6 +9,7 @@ import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
"github.com/skip-mev/block-sdk/block/utils/mocks"
@ -509,6 +510,7 @@ func (s *BaseTestSuite) initLane(
s.encodingConfig.TxConfig.TxEncoder(),
s.encodingConfig.TxConfig.TxDecoder(),
s.setUpAnteHandler(expectedExecution),
signer_extraction.NewDefaultAdapter(),
maxBlockSpace,
)

View File

@ -30,6 +30,7 @@ func NewDefaultLane(cfg base.LaneConfig) *DefaultLane {
base.NewMempool[string](
base.DefaultTxPriority(),
cfg.TxEncoder,
cfg.SignerExtractor,
cfg.MaxTxs,
),
base.DefaultMatchHandler(),

View File

@ -4,6 +4,7 @@ import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block/base"
testutils "github.com/skip-mev/block-sdk/testutils"
)
@ -85,7 +86,7 @@ func (s *BaseTestSuite) TestCompareTxPriority() {
}
func (s *BaseTestSuite) TestInsert() {
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), 3)
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), signer_extraction.NewDefaultAdapter(), 3)
s.Run("should be able to insert a transaction", func() {
tx, err := testutils.CreateRandomTx(
@ -137,7 +138,7 @@ func (s *BaseTestSuite) TestInsert() {
}
func (s *BaseTestSuite) TestRemove() {
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), 3)
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), signer_extraction.NewDefaultAdapter(), 3)
s.Run("should be able to remove a transaction", func() {
tx, err := testutils.CreateRandomTx(
@ -175,7 +176,7 @@ func (s *BaseTestSuite) TestRemove() {
func (s *BaseTestSuite) TestSelect() {
s.Run("should be able to select transactions in the correct order", func() {
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), 3)
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), signer_extraction.NewDefaultAdapter(), 3)
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
@ -214,7 +215,7 @@ func (s *BaseTestSuite) TestSelect() {
})
s.Run("should be able to select a single transaction", func() {
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), 3)
mempool := base.NewMempool[string](base.DefaultTxPriority(), s.encodingConfig.TxConfig.TxEncoder(), signer_extraction.NewDefaultAdapter(), 3)
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,

View File

@ -33,6 +33,7 @@ func NewFreeLane(
base.NewMempool[string](
txPriority,
cfg.TxEncoder,
cfg.SignerExtractor,
cfg.MaxTxs,
),
matchFn,

View File

@ -118,7 +118,7 @@ func (handler *CheckTxHandler) CheckTx() CheckTx {
0,
nil,
false,
), err
), nil
}
// Attempt to get the bid info of the transaction.
@ -135,7 +135,7 @@ func (handler *CheckTxHandler) CheckTx() CheckTx {
0,
nil,
false,
), err
), nil
}
// If this is not a bid transaction, we just execute it normally.
@ -162,17 +162,35 @@ func (handler *CheckTxHandler) CheckTx() CheckTx {
handler.baseApp.Logger().Info(
"invalid bid tx",
"err", err,
"tx", req.Tx,
"removing tx from mempool", true,
)
// attempt to remove the bid from the MEVLane (if it exists)
if handler.mevLane.Contains(tx) {
if err := handler.mevLane.Remove(tx); err != nil {
handler.baseApp.Logger().Error(
"failed to remove bid transaction from mev-lane",
"err", err,
)
}
}
return sdkerrors.ResponseCheckTxWithEvents(
fmt.Errorf("invalid bid tx: %w", err),
gasInfo.GasWanted,
gasInfo.GasUsed,
nil,
false,
), err
), nil
}
handler.baseApp.Logger().Info(
"valid bid tx",
"tx", req.Tx,
"inserting tx into mempool", true,
)
// If the bid transaction is valid, we know we can insert it into the mempool for consideration in the next block.
if err := handler.mevLane.Insert(ctx, tx); err != nil {
handler.baseApp.Logger().Info(
@ -186,7 +204,7 @@ func (handler *CheckTxHandler) CheckTx() CheckTx {
gasInfo.GasUsed,
nil,
false,
), err
), nil
}
return &cometabci.ResponseCheckTx{

View File

@ -4,8 +4,8 @@ import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block/base"
"github.com/skip-mev/block-sdk/x/auction/types"
)
@ -30,7 +30,8 @@ type (
// DefaultAuctionFactory defines a default implmentation for the auction factory interface for processing auction transactions.
DefaultAuctionFactory struct {
txDecoder sdk.TxDecoder
txDecoder sdk.TxDecoder
signerExtractor signer_extraction.Adapter
}
// TxWithTimeoutHeight is used to extract timeouts from sdk.Tx transactions. In the case where,
@ -45,9 +46,10 @@ type (
var _ Factory = (*DefaultAuctionFactory)(nil)
// NewDefaultAuctionFactory returns a default auction factory interface implementation.
func NewDefaultAuctionFactory(txDecoder sdk.TxDecoder) Factory {
func NewDefaultAuctionFactory(txDecoder sdk.TxDecoder, extractor signer_extraction.Adapter) Factory {
return &DefaultAuctionFactory{
txDecoder: txDecoder,
txDecoder: txDecoder,
signerExtractor: extractor,
}
}
@ -115,20 +117,15 @@ func (config *DefaultAuctionFactory) getBundleSigners(bundle [][]byte) ([]map[st
return nil, err
}
sigTx, ok := sdkTx.(signing.SigVerifiableTx)
if !ok {
return nil, fmt.Errorf("transaction is not valid")
}
txSigners := make(map[string]struct{})
signers, err := sigTx.GetSigners()
signers, err := config.signerExtractor.GetSigners(sdkTx)
if err != nil {
return nil, err
}
for _, signer := range signers {
txSigners[sdk.AccAddress(signer).String()] = struct{}{}
txSigners[signer.Signer.String()] = struct{}{}
}
bundleSigners = append(bundleSigners, txSigners)

View File

@ -53,6 +53,7 @@ func NewMEVLane(
base.NewMempool[string](
TxPriority(factory),
cfg.TxEncoder,
cfg.SignerExtractor,
cfg.MaxTxs,
),
factory.MatchHandler(),

View File

@ -10,6 +10,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/lanes/mev"
testutils "github.com/skip-mev/block-sdk/testutils"
)
@ -32,7 +33,7 @@ func TestMempoolTestSuite(t *testing.T) {
func (suite *MEVTestSuite) SetupTest() {
// Mempool setup
suite.encCfg = testutils.CreateTestEncodingConfig()
suite.config = mev.NewDefaultAuctionFactory(suite.encCfg.TxConfig.TxDecoder())
suite.config = mev.NewDefaultAuctionFactory(suite.encCfg.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter())
suite.ctx = sdk.NewContext(nil, cmtproto.Header{}, false, log.NewTestLogger(suite.T()))
// Init accounts

View File

@ -62,6 +62,7 @@ import (
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
"github.com/skip-mev/block-sdk/abci"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
defaultlane "github.com/skip-mev/block-sdk/lanes/base"
@ -264,24 +265,26 @@ func New(
// lane and the last lane is the lowest priority lane.
// MEV lane allows transactions to bid for inclusion at the top of the next block.
mevConfig := base.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(), // This means the lane has no limit on block space.
MaxTxs: 0, // This means the lane has no limit on the number of transactions it can store.
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(), // This means the lane has no limit on block space.
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxTxs: 0, // This means the lane has no limit on the number of transactions it can store.
}
mevLane := mev.NewMEVLane(
mevConfig,
mev.NewDefaultAuctionFactory(app.txConfig.TxDecoder()),
mev.NewDefaultAuctionFactory(app.txConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()),
)
// Free lane allows transactions to be included in the next block for free.
freeConfig := base.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(),
MaxTxs: 0,
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxTxs: 0,
}
freeLane := free.NewFreeLane(
freeConfig,
@ -291,11 +294,12 @@ func New(
// Default lane accepts all other transactions.
defaultConfig := base.LaneConfig{
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(),
MaxTxs: 0,
Logger: app.Logger(),
TxEncoder: app.txConfig.TxEncoder(),
TxDecoder: app.txConfig.TxDecoder(),
MaxBlockSpace: math.LegacyZeroDec(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxTxs: 0,
}
defaultLane := defaultlane.NewDefaultLane(defaultConfig)

View File

@ -12,6 +12,10 @@ import (
"github.com/strangelove-ventures/interchaintest/v7/ibc"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
rpctypes "github.com/cometbft/cometbft/rpc/core/types"
"bytes"
)
const (
@ -31,6 +35,12 @@ type IntegrationTestSuite struct {
user1, user2, user3 ibc.Wallet
// denom
denom string
// overrides for key-ring configuration of the broadcaster
broadcasterOverrides *KeyringOverride
// broadcaster is the RPC interface to the ITS network
bc *cosmos.Broadcaster
}
func NewIntegrationTestSuiteFromSpec(spec *interchaintest.ChainSpec) *IntegrationTestSuite {
@ -50,6 +60,13 @@ func (s *IntegrationTestSuite) WithDenom(denom string) *IntegrationTestSuite {
return s
}
func (s *IntegrationTestSuite) WithKeyringOptions(cdc codec.Codec, opts keyring.Option) {
s.broadcasterOverrides = &KeyringOverride{
cdc: cdc,
keyringOptions: opts,
}
}
func (s *IntegrationTestSuite) SetupSuite() {
// build the chain
s.T().Log("building chain with spec", s.spec)
@ -64,6 +81,10 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.user1 = interchaintest.GetAndFundTestUsers(s.T(), ctx, s.T().Name(), initBalance, s.chain)[0]
s.user2 = interchaintest.GetAndFundTestUsers(s.T(), ctx, s.T().Name(), initBalance, s.chain)[0]
s.user3 = interchaintest.GetAndFundTestUsers(s.T(), ctx, s.T().Name(), initBalance, s.chain)[0]
// create the broadcaster
s.T().Log("creating broadcaster")
s.setupBroadcaster()
}
func (s *IntegrationTestSuite) TearDownSuite() {
@ -108,7 +129,7 @@ func (s *IntegrationTestSuite) TestValidBids() {
// create the MsgAuctioBid
bidAmt := params.ReserveFee
bid, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
bid, bundledTxs := s.CreateAuctionBidMsg(context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{
@ -122,7 +143,7 @@ func (s *IntegrationTestSuite) TestValidBids() {
require.NoError(s.T(), err)
// broadcast + wait for the tx to be included in a block
res := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
res := s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
@ -156,7 +177,7 @@ func (s *IntegrationTestSuite) TestValidBids() {
// create the MsgAuctionBid
bidAmt := params.ReserveFee
bid, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
bid, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
{
User: s.user1,
Msgs: msgs[0:1],
@ -172,24 +193,52 @@ func (s *IntegrationTestSuite) TestValidBids() {
msgsToBcast = append(msgsToBcast, Tx{
User: s.user1,
Msgs: []sdk.Msg{bid},
Height: height + 1,
Height: height + 3,
})
msgsToBcast = append(msgsToBcast, Tx{
User: s.user2,
Msgs: msgs[1:2],
Height: height + 1,
Height: height + 3,
})
regular_txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), msgsToBcast)
expTxs := make(chan committedTx, 2)
regular_txs := s.BroadcastTxsWithCallback(
context.Background(),
s.chain.(*cosmos.CosmosChain),
msgsToBcast,
func(tx []byte, resp *rpctypes.ResultTx) {
expTxs <- committedTx{tx, resp}
},
)
close(expTxs)
s.Require().Len(expTxs, 2)
// get the height of the block that the bid was included in
var commitHeight int64
tx1 := <-expTxs
tx2 := <-expTxs
// determine which tx is the bid
if bytes.Equal(tx1.tx, regular_txs[0]) {
commitHeight = tx1.res.Height
} else {
commitHeight = tx2.res.Height
}
// if they were committed in the same height
if tx1.res.Height == tx2.res.Height {
bundledTxs = append(bundledTxs, regular_txs[1:]...)
}
// get the block at the next height
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), commitHeight)
// verify the block
bidTxHash := TxHash(regular_txs[0])
VerifyBlock(s.T(), block, 0, bidTxHash, append(bundledTxs, regular_txs[1:]...))
VerifyBlock(s.T(), block, 0, bidTxHash, bundledTxs)
// ensure that escrow account has the correct balance
escrowAcctBalanceAfterBid := QueryAccountBalance(s.T(), s.chain, escrowAddr, params.ReserveFee.Denom)
@ -216,10 +265,10 @@ func (s *IntegrationTestSuite) TestValidBids() {
}
// create bundle
bidAmt := params.ReserveFee
bid, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, txs)
bid, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, txs)
// create 2 more bundle w same txs from same user
bid2, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), txs)
bid3, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement).Add(params.MinBidIncrement), txs)
bid2, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), txs)
bid3, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement).Add(params.MinBidIncrement), txs)
// query height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
@ -230,7 +279,7 @@ func (s *IntegrationTestSuite) TestValidBids() {
height++
// broadcast all bids
broadcastedTxs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
broadcastedTxs := s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
@ -286,28 +335,41 @@ func (s *IntegrationTestSuite) TestValidBids() {
// create bundle
bidAmt := params.ReserveFee
bid, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt, txs)
bid, bundledTxs := s.CreateAuctionBidMsg(context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt, txs)
// get chain height
height, err = s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
expTxs := make(chan committedTx, 4)
// broadcast txs in the bundle to network + bundle + extra
broadcastedTxs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{txs[0], txs[1], {
broadcastedTxs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user2,
Msgs: []sdk.Msg{bid},
Height: height + 1,
Height: height + 3,
}, {
User: s.user3,
Msgs: []sdk.Msg{banktypes.NewMsgSend(s.user3.Address(), s.user1.Address(), sdk.NewCoins(sdk.NewCoin(s.denom, math.NewInt(100))))},
}})
Height: height + 3,
}},
func(tx []byte, resp *rpctypes.ResultTx) {
expTxs <- committedTx{tx, resp}
})
close(expTxs)
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
var bidTxHeight int64
for tx := range expTxs {
if bytes.Equal(tx.tx, broadcastedTxs[0]) {
bidTxHeight = tx.res.Height
}
}
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), bidTxHeight)
// check block
VerifyBlock(s.T(), block, 0, TxHash(broadcastedTxs[2]), append(bundledTxs, broadcastedTxs[3]))
VerifyBlock(s.T(), block, 0, TxHash(broadcastedTxs[0]), bundledTxs)
// check escrow account balance
escrowAcctBalanceAfterBid := QueryAccountBalance(s.T(), s.chain, escrowAddr, params.ReserveFee.Denom)
@ -316,6 +378,11 @@ func (s *IntegrationTestSuite) TestValidBids() {
})
}
type committedTx struct {
tx []byte
res *rpctypes.ResultTx
}
// TestMultipleBids tests the execution of various valid auction bids in the same block. There are a few
// invariants that are tested:
//
@ -343,7 +410,7 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
}
// create bid1
bidAmt := params.ReserveFee
bid1, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid1, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
// create bid 2
msg2 := Tx{
@ -352,36 +419,45 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
SequenceIncrement: 1,
}
// create bid2 w/ higher bid than bid1
bid2, bundledTxs2 := CreateAuctionBidMsg(s.T(), context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg2})
bid2, bundledTxs2 := s.CreateAuctionBidMsg( context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg2})
// get chain height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast both bids
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
// create channel to receive txs
txsCh := make(chan committedTx, 2)
// broadcast both bids (with ample time to be committed (instead of timing out))
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid1},
Height: height + 2,
SkipInclusionCheck: true,
Height: height + 4,
},
{
User: s.user2,
Msgs: []sdk.Msg{bid2},
Height: height + 1,
Height: height + 3,
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
txsCh <- committedTx{tx, resp}
})
// check txs were committed
require.Len(s.T(), txsCh, 2)
close(txsCh)
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
tx1 := <-txsCh
tx2 := <-txsCh
// query next block
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), tx1.res.Height)
// check bid2 was included first
VerifyBlock(s.T(), block, 0, TxHash(txs[1]), bundledTxs2)
// check next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+2)
block = Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+2))
block = Block(s.T(), s.chain.(*cosmos.CosmosChain), tx2.res.Height)
// check bid1 was included second
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTxs)
@ -405,7 +481,7 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
}
// create bid1
bidAmt := params.ReserveFee
bid1, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{tx})
bid1, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{tx})
// create bid 2
tx2 := Tx{
@ -414,30 +490,36 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
SequenceIncrement: 1,
}
// create bid2 w/ higher bid than bid1
bid2, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{tx2})
bid2, _ := s.CreateAuctionBidMsg( context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{tx2})
// get chain height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast both bids
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
expTx := make(chan committedTx, 1)
// broadcast both bids (wait for the first to be committed)
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid1},
Height: height + 1,
Height: height + 4,
},
{
User: s.user2,
Msgs: []sdk.Msg{bid2},
Height: height + 1,
Height: height + 3,
ExpectFail: true,
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
expTx <- committedTx{tx, resp}
})
close(expTx)
commitTx := <-expTx
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), commitTx.res.Height)
// check bid2 was included first
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTxs)
@ -461,7 +543,7 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
}
// create bid1
bidAmt := params.ReserveFee
bid1, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid1, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
// create bid 2
msg2 := Tx{
@ -469,33 +551,39 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
Msgs: []sdk.Msg{banktypes.NewMsgSend(s.user2.Address(), s.user3.Address(), sdk.NewCoins(sdk.NewCoin(s.denom, math.NewInt(100))))},
SequenceIncrement: 1,
}
// create bid2 w/ higher bid than bid1
bid2, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg2})
bid2, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg2})
// get chain height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
expTx := make(chan committedTx, 1)
// broadcast both bids
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid1},
Height: height + 1,
Height: height + 4,
},
{
User: s.user1,
Msgs: []sdk.Msg{bid2},
SequenceIncrement: 1,
Height: height + 1,
Height: height + 4,
ExpectFail: true,
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
expTx <- committedTx{tx, resp}
})
close(expTx)
commitTx := <-expTx
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), commitTx.res.Height)
// check bid2 was included first
// check bid1 was included first
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTxs)
// check escrow balance
@ -517,41 +605,49 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
}
// create bid1
bidAmt := params.ReserveFee
bid1, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid1, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
// create bid2 w/ higher bid than bid1
bid2, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg})
bid2, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg})
// get chain height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
commitTx := make(chan committedTx, 1)
// broadcast both bids
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid2},
Height: height + 1,
},
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid1},
Height: height + 2,
SequenceIncrement: 1,
ExpectFail: true,
Height: height + 4,
SkipInclusionCheck: true,
},
{
User: s.user1,
Msgs: []sdk.Msg{bid2},
Height: height + 3,
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
commitTx <- committedTx{tx, resp}
})
close(commitTx)
expTx := <-commitTx
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), expTx.res.Height)
// check bid2 was included first
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTxs)
VerifyBlock(s.T(), block, 0, TxHash(txs[1]), bundledTxs)
// check escrow balance
escrowAcctBalanceAfterBid := QueryAccountBalance(s.T(), s.chain, escrowAddr, params.ReserveFee.Denom)
expectedIncrement := escrowAddressIncrement(bidAmt.Add(params.MinBidIncrement).Amount, params.ProposerFee)
require.Equal(s.T(), escrowAcctBalanceBeforeBid+expectedIncrement, escrowAcctBalanceAfterBid)
// wait for next block for mempool to clear
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+3)
})
s.Run("Multiple transactions from diff. account with increasing bids but first bid has same bundle so it should fail in later block", func() {
@ -567,40 +663,49 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
// create bid1
bidAmt := params.ReserveFee
bid1, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid1, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
// create bid2 w/ higher bid than bid1
bid2, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg})
bid2, _ := s.CreateAuctionBidMsg( context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg})
// get chain height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
commitTx := make(chan committedTx, 1)
// broadcast both bids
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user2,
Msgs: []sdk.Msg{bid2},
Height: height + 1,
},
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid1},
Height: height + 1,
ExpectFail: true,
Height: height + 4,
SkipInclusionCheck: true,
},
{
User: s.user2,
Msgs: []sdk.Msg{bid2},
Height: height + 3,
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
commitTx <- committedTx{tx, resp}
})
close(commitTx)
expTx := <-commitTx
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), expTx.res.Height)
// check bid2 was included first
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTxs)
VerifyBlock(s.T(), block, 0, TxHash(txs[1]), bundledTxs)
// check escrow balance
escrowAcctBalanceAfterBid := QueryAccountBalance(s.T(), s.chain, escrowAddr, params.ReserveFee.Denom)
expectedIncrement := escrowAddressIncrement(bidAmt.Add(params.MinBidIncrement).Amount, params.ProposerFee)
require.Equal(s.T(), escrowAcctBalanceBeforeBid+expectedIncrement, escrowAcctBalanceAfterBid)
// wait for next block for mempool to clear
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+3)
})
s.Run("Multiple transactions with increasing bids and different bundles", func() {
@ -616,7 +721,7 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
}
// create bid1
bidAmt := params.ReserveFee
bid1, bundledTxs := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid1, bundledTxs := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
// create bid2
// create a second message
@ -627,36 +732,48 @@ func (s *IntegrationTestSuite) TestMultipleBids() {
}
// create bid2 w/ higher bid than bid1
bid2, bundledTxs2 := CreateAuctionBidMsg(s.T(), context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg2})
bid2, bundledTxs2 := s.CreateAuctionBidMsg(context.Background(), s.user2, s.chain.(*cosmos.CosmosChain), bidAmt.Add(params.MinBidIncrement), []Tx{msg2})
// get chain height
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// make channel for committedTxs (expect 2 txs to be committed)
committedTxs := make(chan committedTx, 2)
// broadcast both bids
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid1},
Height: height + 2,
SkipInclusionCheck: true,
Height: height + 4,
},
{
User: s.user2,
Msgs: []sdk.Msg{bid2},
Height: height + 1,
Height: height + 3,
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
committedTxs <- committedTx{
tx: tx,
res: resp,
}
})
// close the channel when finished
close(committedTxs)
// expect 2 txs
tx1 := <-committedTxs
tx2 := <-committedTxs
// query next block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), tx1.res.Height)
// check bid2 was included first
VerifyBlock(s.T(), block, 0, TxHash(txs[1]), bundledTxs2)
// query next block and check tx inclusion
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+2)
block = Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+2))
block = Block(s.T(), s.chain.(*cosmos.CosmosChain), tx2.res.Height)
// check bid1 was included second
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTxs)
@ -680,11 +797,11 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
SequenceIncrement: 2,
}
bidAmt := params.ReserveFee
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
// wrap bidTx in another tx
wrappedBid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
wrappedBid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
@ -696,7 +813,7 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
require.NoError(s.T(), err)
// broadcast wrapped bid, and expect a failure
BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{wrappedBid},
@ -714,13 +831,13 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
SequenceIncrement: 2,
}
bidAmt := sdk.NewCoin(s.denom, math.NewInt(1000000000000000000))
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast wrapped bid, and expect a failure
SimulateTx(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
s.SimulateTx(context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
})
s.Run("Invalid bid that is attempting to front-run/sandwich", func() {
@ -741,13 +858,13 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
}
bidAmt := params.ReserveFee
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg, msg2, msg3})
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg, msg2, msg3})
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast wrapped bid, and expect a failure
SimulateTx(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
s.SimulateTx(context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
})
s.Run("Invalid bid that includes an invalid bundle tx", func() {
@ -758,13 +875,13 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
SequenceIncrement: 2,
}
bidAmt := params.ReserveFee
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast wrapped bid, and expect a failure
BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
@ -784,13 +901,13 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
// create bid smaller than reserve
bidAmt := sdk.NewCoin(s.denom, math.NewInt(0))
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast wrapped bid, and expect a failure
SimulateTx(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
s.SimulateTx(context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
})
s.Run("Invalid auction bid with too many transactions in the bundle", func() {
@ -807,13 +924,13 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
// create bid smaller than reserve
bidAmt := sdk.NewCoin(s.denom, math.NewInt(0))
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, msgs)
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, msgs)
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
// broadcast wrapped bid, and expect a failure
SimulateTx(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
s.SimulateTx(context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, height+1, true, []sdk.Msg{bid}...)
})
s.Run("invalid auction bid that has an invalid timeout", func() {
@ -826,10 +943,10 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
// create bid smaller than reserve
bidAmt := sdk.NewCoin(s.denom, math.NewInt(0))
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{msg})
// broadcast wrapped bid, and expect a failure
SimulateTx(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, 0, true, []sdk.Msg{bid}...)
s.SimulateTx(context.Background(), s.chain.(*cosmos.CosmosChain), s.user1, 0, true, []sdk.Msg{bid}...)
})
s.Run("Invalid bid that includes valid transactions that are in the mempool", func() {
@ -842,7 +959,7 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
// create the MsgAuctioBid (this should fail b.c same tx is repeated twice)
bidAmt := params.ReserveFee
bid, _ := CreateAuctionBidMsg(s.T(), context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
bid, _ := s.CreateAuctionBidMsg( context.Background(), s.user1, s.chain.(*cosmos.CosmosChain), bidAmt, []Tx{
{
User: s.user2,
Msgs: []sdk.Msg{
@ -859,7 +976,7 @@ func (s *IntegrationTestSuite) TestInvalidBids() {
require.NoError(s.T(), err)
// broadcast + wait for the tx to be included in a block
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
txs := s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
@ -905,7 +1022,7 @@ func (s *IntegrationTestSuite) TestFreeLane() {
balanceBefore := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user1.FormattedAddress(), s.denom)
// create a free tx (MsgDelegate), broadcast and wait for commit
BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{
@ -929,7 +1046,7 @@ func (s *IntegrationTestSuite) TestFreeLane() {
user2BalanceBefore := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user2.FormattedAddress(), s.denom)
// user1 submits a free-tx, user2 submits a normal tx
BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
s.BroadcastTxs(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{
@ -968,7 +1085,7 @@ func (s *IntegrationTestSuite) TestFreeLane() {
user2BalanceBefore := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user2.FormattedAddress(), s.denom)
// user1 submits a free-tx, user2 submits a free tx
BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{
@ -1012,8 +1129,7 @@ func (s *IntegrationTestSuite) TestLanes() {
user2BalanceBefore := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user2.FormattedAddress(), s.denom)
// create free-tx, bid-tx, and normal-tx\
bid, bundledTx := CreateAuctionBidMsg(
s.T(),
bid, bundledTx := s.CreateAuctionBidMsg(
context.Background(),
s.user1,
s.chain.(*cosmos.CosmosChain),
@ -1036,11 +1152,13 @@ func (s *IntegrationTestSuite) TestLanes() {
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
committedTxs := make(chan committedTx, 3)
txs := s.BroadcastTxsWithCallback(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
Height: height + 1,
Height: height + 3,
},
{
User: s.user2,
@ -1063,13 +1181,23 @@ func (s *IntegrationTestSuite) TestLanes() {
},
},
},
}, func(tx []byte, resp *rpctypes.ResultTx) {
committedTxs <- committedTx{tx: tx, res: resp}
})
close(committedTxs)
// check block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
// find height of committed tx
var committedHeight int64
for tx := range committedTxs {
if bytes.Equal(tx.tx, txs[0]) {
committedHeight = tx.res.Height
break
}
}
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), append(bundledTx, txs[1:]...))
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), committedHeight)
VerifyBlock(s.T(), block, 0, TxHash(txs[0]), bundledTx)
// check user2 balance expect no fee deduction
user2BalanceAfter := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user2.FormattedAddress(), s.denom)
@ -1080,8 +1208,7 @@ func (s *IntegrationTestSuite) TestLanes() {
user2BalanceBefore := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user2.FormattedAddress(), s.denom)
user1Balance := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user1.FormattedAddress(), s.denom)
// create free-tx, bid-tx, and normal-tx\
bid, _ := CreateAuctionBidMsg(
s.T(),
bid, _ := s.CreateAuctionBidMsg(
context.Background(),
s.user1,
s.chain.(*cosmos.CosmosChain),
@ -1115,7 +1242,7 @@ func (s *IntegrationTestSuite) TestLanes() {
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user1,
Msgs: []sdk.Msg{bid},
@ -1145,12 +1272,6 @@ func (s *IntegrationTestSuite) TestLanes() {
},
})
// check block
WaitForHeight(s.T(), s.chain.(*cosmos.CosmosChain), height+1)
block := Block(s.T(), s.chain.(*cosmos.CosmosChain), int64(height+1))
VerifyBlock(s.T(), block, 0, "", txs[1:])
// check user2 balance expect no fee deduction
user2BalanceAfter := QueryAccountBalance(s.T(), s.chain.(*cosmos.CosmosChain), s.user2.FormattedAddress(), s.denom)
require.Equal(s.T(), user2BalanceBefore, user2BalanceAfter+delegation.Amount.Int64())
@ -1171,8 +1292,7 @@ func (s *IntegrationTestSuite) TestLanes() {
GasPrice: 10,
}
bid, bundledTx := CreateAuctionBidMsg(
s.T(),
bid, bundledTx := s.CreateAuctionBidMsg(
context.Background(),
s.user3,
s.chain.(*cosmos.CosmosChain),
@ -1196,7 +1316,7 @@ func (s *IntegrationTestSuite) TestLanes() {
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
txs := s.BroadcastTxs(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user3,
Msgs: []sdk.Msg{bid},
@ -1248,8 +1368,7 @@ func (s *IntegrationTestSuite) TestLanes() {
// create bid-tx w/ user3 DelegateTx
bid, bundledTx := CreateAuctionBidMsg(
s.T(),
bid, bundledTx := s.CreateAuctionBidMsg(
context.Background(),
s.user3,
s.chain.(*cosmos.CosmosChain),
@ -1273,7 +1392,7 @@ func (s *IntegrationTestSuite) TestLanes() {
height, err := s.chain.(*cosmos.CosmosChain).Height(context.Background())
require.NoError(s.T(), err)
txs := BroadcastTxs(s.T(), context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
txs := s.BroadcastTxs( context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{
{
User: s.user3,
Msgs: []sdk.Msg{bid},

View File

@ -7,6 +7,14 @@ import (
"strings"
"testing"
"time"
"os"
"io"
"path"
"archive/tar"
"bytes"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"cosmossdk.io/math"
rpctypes "github.com/cometbft/cometbft/rpc/core/types"
@ -29,6 +37,11 @@ import (
auctiontypes "github.com/skip-mev/block-sdk/x/auction/types"
)
type KeyringOverride struct {
keyringOptions keyring.Option
cdc codec.Codec
}
// ChainBuilderFromChainSpec creates an interchaintest chain builder factory given a ChainSpec
// and returns the associated chain
func ChainBuilderFromChainSpec(t *testing.T, spec *interchaintest.ChainSpec) ibc.Chain {
@ -73,19 +86,18 @@ func BuildInterchain(t *testing.T, ctx context.Context, chain ibc.Chain) *interc
}
// CreateTx creates a new transaction to be signed by the given user, including a provided set of messages
func CreateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user cosmos.User, seqIncrement, height uint64, GasPrice int64, msgs ...sdk.Msg) []byte {
// create a broadcaster
broadcaster := cosmos.NewBroadcaster(t, chain)
func (s *IntegrationTestSuite) CreateTx(ctx context.Context, chain *cosmos.CosmosChain, user cosmos.User, seqIncrement, height uint64, GasPrice int64, msgs ...sdk.Msg) []byte {
// create tx factory + Client Context
txf, err := broadcaster.GetFactory(ctx, user)
require.NoError(t, err)
txf, err := s.bc.GetFactory(ctx, user)
s.Require().NoError(err)
cc, err := broadcaster.GetClientContext(ctx, user)
require.NoError(t, err)
cc, err := s.bc.GetClientContext(ctx, user)
s.Require().NoError(err)
txf = txf.WithSimulateAndExecute(true)
txf, err = txf.Prepare(cc)
require.NoError(t, err)
s.Require().NoError(err)
// set timeout height
if height != 0 {
@ -94,7 +106,7 @@ func CreateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user
// get gas for tx
_, gas, err := tx.CalculateGas(cc, txf, msgs...)
require.NoError(t, err)
s.Require().NoError(err)
txf.WithGas(gas)
// update sequence number
@ -103,30 +115,27 @@ func CreateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user
// sign the tx
txBuilder, err := txf.BuildUnsignedTx(msgs...)
require.NoError(t, err)
s.Require().NoError(err)
require.NoError(t, tx.Sign(ctx, txf, cc.GetFromName(), txBuilder, true))
s.Require().NoError(tx.Sign(cc.CmdContext, txf, cc.GetFromName(), txBuilder, true))
// encode and return
bz, err := cc.TxConfig.TxEncoder()(txBuilder.GetTx())
require.NoError(t, err)
s.Require().NoError(err)
return bz
}
// SimulateTx simulates the provided messages, and checks whether the provided failure condition is met
func SimulateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, user cosmos.User, height uint64, expectFail bool, msgs ...sdk.Msg) {
// create a broadcaster
broadcaster := cosmos.NewBroadcaster(t, chain)
func (s *IntegrationTestSuite) SimulateTx(ctx context.Context, chain *cosmos.CosmosChain, user cosmos.User, height uint64, expectFail bool, msgs ...sdk.Msg) {
// create tx factory + Client Context
txf, err := broadcaster.GetFactory(ctx, user)
require.NoError(t, err)
txf, err := s.bc.GetFactory(ctx, user)
s.Require().NoError(err)
cc, err := broadcaster.GetClientContext(ctx, user)
require.NoError(t, err)
cc, err := s.bc.GetClientContext(ctx, user)
s.Require().NoError(err)
txf, err = txf.Prepare(cc)
require.NoError(t, err)
s.Require().NoError(err)
// set timeout height
if height != 0 {
@ -135,7 +144,7 @@ func SimulateTx(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, us
// get gas for tx
_, _, err = tx.CalculateGas(cc, txf, msgs...)
require.Equal(t, err != nil, expectFail)
s.Require().Equal(err != nil, expectFail)
}
type Tx struct {
@ -149,16 +158,16 @@ type Tx struct {
}
// CreateAuctionBidMsg creates a new AuctionBid tx signed by the given user, the order of txs in the MsgAuctionBid will be determined by the contents + order of the MessageForUsers
func CreateAuctionBidMsg(t *testing.T, ctx context.Context, searcher cosmos.User, chain *cosmos.CosmosChain, bid sdk.Coin, txsPerUser []Tx) (*auctiontypes.MsgAuctionBid, [][]byte) {
func (s *IntegrationTestSuite) CreateAuctionBidMsg(ctx context.Context, searcher cosmos.User, chain *cosmos.CosmosChain, bid sdk.Coin, txsPerUser []Tx) (*auctiontypes.MsgAuctionBid, [][]byte) {
// for each MessagesForUser get the signed bytes
txs := make([][]byte, len(txsPerUser))
for i, tx := range txsPerUser {
txs[i] = CreateTx(t, ctx, chain, tx.User, tx.SequenceIncrement, tx.Height, tx.GasPrice, tx.Msgs...)
txs[i] = s.CreateTx(ctx, chain, tx.User, tx.SequenceIncrement, tx.Height, tx.GasPrice, tx.Msgs...)
}
bech32SearcherAddress := searcher.FormattedAddress()
accAddr, err := sdk.AccAddressFromBech32(bech32SearcherAddress)
require.NoError(t, err)
s.Require().NoError(err)
// create a message auction bid
return auctiontypes.NewMsgAuctionBid(
@ -171,26 +180,43 @@ func CreateAuctionBidMsg(t *testing.T, ctx context.Context, searcher cosmos.User
// BroadcastTxs broadcasts the given messages for each user. This function returns the broadcasted txs. If a message
// is not expected to be included in a block, set SkipInclusionCheck to true and the method
// will not block on the tx's inclusion in a block, otherwise this method will block on the tx's inclusion
func BroadcastTxs(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain, msgsPerUser []Tx) [][]byte {
func (s *IntegrationTestSuite) BroadcastTxs(ctx context.Context, chain *cosmos.CosmosChain, msgsPerUser []Tx) [][]byte {
return s.BroadcastTxsWithCallback(ctx, chain, msgsPerUser, nil)
}
// BroadcastTxs broadcasts the given messages for each user. This function returns the broadcasted txs. If a message
// is not expected to be included in a block, set SkipInclusionCheck to true and the method
// will not block on the tx's inclusion in a block, otherwise this method will block on the tx's inclusion. The callback
// function is called for each tx that is included in a block.
func (s *IntegrationTestSuite) BroadcastTxsWithCallback(
ctx context.Context,
chain *cosmos.CosmosChain,
msgsPerUser []Tx,
cb func(tx []byte, resp *rpctypes.ResultTx),
) [][]byte {
txs := make([][]byte, len(msgsPerUser))
for i, msg := range msgsPerUser {
txs[i] = CreateTx(t, ctx, chain, msg.User, msg.SequenceIncrement, msg.Height, msg.GasPrice, msg.Msgs...)
txs[i] = s.CreateTx(ctx, chain, msg.User, msg.SequenceIncrement, msg.Height, msg.GasPrice, msg.Msgs...)
}
// broadcast each tx
require.True(t, len(chain.Nodes()) > 0)
s.Require().True(len(chain.Nodes()) > 0)
client := chain.Nodes()[0].Client
for i, tx := range txs {
// broadcast tx
_, err := client.BroadcastTxSync(ctx, tx)
resp, err := client.BroadcastTxSync(ctx, tx)
// check execution was successful
if !msgsPerUser[i].ExpectFail {
require.NoError(t, err)
s.Require().Equal(resp.Code, uint32(0))
} else {
require.Error(t, err)
if resp != nil {
s.Require().NotEqual(resp.Code, uint32(0))
} else {
s.Require().Error(err)
}
}
}
@ -205,18 +231,22 @@ func BroadcastTxs(t *testing.T, ctx context.Context, chain *cosmos.CosmosChain,
tx := tx // pin
eg.Go(func() error {
return testutil.WaitForCondition(4*time.Second, 500*time.Millisecond, func() (bool, error) {
return testutil.WaitForCondition(30*time.Second, 500*time.Millisecond, func() (bool, error) {
res, err := client.Tx(context.Background(), comettypes.Tx(tx).Hash(), false)
if err != nil || res.TxResult.Code != uint32(0) {
return false, nil
}
if cb != nil {
cb(tx, res)
}
return true, nil
})
})
}
require.NoError(t, eg.Wait())
s.Require().NoError(eg.Wait())
return txs
}
@ -313,12 +343,12 @@ func Block(t *testing.T, chain *cosmos.CosmosChain, height int64) *rpctypes.Resu
// WaitForHeight waits for the chain to reach the given height
func WaitForHeight(t *testing.T, chain *cosmos.CosmosChain, height uint64) {
// wait for next height
err := testutil.WaitForCondition(30*time.Second, time.Second, func() (bool, error) {
err := testutil.WaitForCondition(30*time.Second, 100 * time.Millisecond, func() (bool, error) {
pollHeight, err := chain.Height(context.Background())
if err != nil {
return false, err
}
return pollHeight == height, nil
return pollHeight >= height, nil
})
require.NoError(t, err)
}
@ -340,3 +370,73 @@ func VerifyBlock(t *testing.T, block *rpctypes.ResultBlock, offset int, bidTxHas
func TxHash(tx []byte) string {
return strings.ToUpper(hex.EncodeToString(comettypes.Tx(tx).Hash()))
}
func (s *IntegrationTestSuite) setupBroadcaster() {
bc := cosmos.NewBroadcaster(s.T(), s.chain.(*cosmos.CosmosChain))
if s.broadcasterOverrides == nil {
s.bc = bc
return
}
// get the key-ring-dir from the node locally
keyringDir := s.keyringDirFromNode()
// create a new keyring
kr, err := keyring.New("", keyring.BackendTest, keyringDir, os.Stdin, s.broadcasterOverrides.cdc, s.broadcasterOverrides.keyringOptions)
s.Require().NoError(err)
// override factory + client context keyrings
bc.ConfigureFactoryOptions(
func(factory tx.Factory) tx.Factory {
return factory.WithKeybase(kr)
},
)
bc.ConfigureClientContextOptions(
func(cc client.Context) client.Context {
return cc.WithKeyring(kr)
},
)
s.bc = bc
}
// sniped from here: https://github.com/strangelove-ventures/interchaintest ref: 9341b001214d26be420f1ca1ab0f15bad17faee6
func (s *IntegrationTestSuite) keyringDirFromNode() (string) {
node := s.chain.(*cosmos.CosmosChain).Nodes()[0]
// create a temp-dir
localDir := s.T().TempDir()
containerKeyringDir := path.Join(node.HomeDir(), "keyring-test")
reader, _, err := node.DockerClient.CopyFromContainer(context.Background(), node.ContainerID(), containerKeyringDir)
s.Require().NoError(err)
s.Require().NoError(os.Mkdir(path.Join(localDir, "keyring-test"), os.ModePerm))
tr := tar.NewReader(reader)
for {
hdr, err := tr.Next()
if err == io.EOF {
break // End of archive
}
s.Require().NoError(err)
var fileBuff bytes.Buffer
_, err = io.Copy(&fileBuff, tr)
s.Require().NoError(err)
name := hdr.Name
extractedFileName := path.Base(name)
isDirectory := extractedFileName == ""
if isDirectory {
continue
}
filePath := path.Join(localDir, "keyring-test", extractedFileName)
s.Require().NoError(os.WriteFile(filePath, fileBuff.Bytes(), os.ModePerm))
}
return localDir
}

View File

@ -16,9 +16,9 @@ require (
github.com/cometbft/cometbft v0.38.0
github.com/cosmos/cosmos-sdk v0.50.0-rc.0
github.com/skip-mev/block-sdk v1.0.0 // reference local
github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230721183422-fb937bb0e165
github.com/strangelove-ventures/interchaintest/v7 v7.0.0-20230905210439-3e17efc70581
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.24.0
go.uber.org/zap v1.25.0
golang.org/x/sync v0.3.0
google.golang.org/grpc v1.58.1
)
@ -46,7 +46,7 @@ require (
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/avast/retry-go/v4 v4.5.0 // indirect
github.com/aws/aws-sdk-go v1.44.224 // indirect
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
@ -185,7 +185,6 @@ require (
github.com/zondax/ledger-go v0.14.1 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 // indirect

View File

@ -266,8 +266,9 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX
github.com/aws/aws-sdk-go v1.44.224 h1:09CiaaF35nRmxrzWZ2uRq5v6Ghg/d2RiPjZnSgtt+RQ=
github.com/aws/aws-sdk-go v1.44.224/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -1069,11 +1070,9 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
@ -1083,8 +1082,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c=
go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

View File

@ -48,13 +48,6 @@ func NewAuctionDecorator(ak keeper.Keeper, txEncoder sdk.TxEncoder, lane MEVLane
// AnteHandle validates that the auction bid is valid if one exists. If valid it will deduct the entrance fee from the
// bidder's account.
func (ad AuctionDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// If comet is re-checking a transaction, we only need to check if the transaction is in the application-side mempool.
if ctx.IsReCheckTx() {
if !ad.mempool.Contains(tx) {
return ctx, fmt.Errorf("transaction not found in application-side mempool")
}
}
bidInfo, err := ad.lane.GetAuctionBidInfo(tx)
if err != nil {
return ctx, err
@ -62,6 +55,13 @@ func (ad AuctionDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
// Validate the auction bid if one exists.
if bidInfo != nil {
// If comet is re-checking a transaction, we only need to check if the transaction is in the application-side mempool.
if ctx.IsReCheckTx() {
if !ad.mempool.Contains(tx) {
return ctx, fmt.Errorf("transaction not found in application-side mempool")
}
}
// Auction transactions must have a timeout set to a valid block height.
if err := ad.ValidateTimeout(ctx, int64(bidInfo.Timeout)); err != nil {
return ctx, err
@ -71,6 +71,7 @@ func (ad AuctionDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool,
// is checkTx or recheckTx. Otherwise, the ABCI handlers (VerifyVoteExtension, ExtendVoteExtension, etc.)
// will always compare the auction bid to the highest bidding transaction in the mempool leading to
// poor liveness guarantees.
// TODO(nikhil/david): refactor this logic (is this necessary?)
topBid := sdk.Coin{}
if ctx.IsCheckTx() || ctx.IsReCheckTx() {
if topBidTx := ad.lane.GetTopAuctionTx(ctx); topBidTx != nil {

View File

@ -13,6 +13,7 @@ import (
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/suite"
signer_extraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
defaultlane "github.com/skip-mev/block-sdk/lanes/base"
@ -86,25 +87,27 @@ func (suite *AnteTestSuite) SetupTest() {
//
// TOB lane set up
mevConfig := base.LaneConfig{
Logger: suite.ctx.Logger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: suite.anteHandler,
MaxBlockSpace: math.LegacyZeroDec(),
Logger: suite.ctx.Logger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
SignerExtractor: signer_extraction.NewDefaultAdapter(),
AnteHandler: suite.anteHandler,
MaxBlockSpace: math.LegacyZeroDec(),
}
suite.mevLane = mev.NewMEVLane(
mevConfig,
mev.NewDefaultAuctionFactory(suite.encodingConfig.TxConfig.TxDecoder()),
mev.NewDefaultAuctionFactory(suite.encodingConfig.TxConfig.TxDecoder(), signer_extraction.NewDefaultAdapter()),
)
// Base lane set up
baseConfig := base.LaneConfig{
Logger: suite.ctx.Logger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: suite.anteHandler,
MaxBlockSpace: math.LegacyZeroDec(),
IgnoreList: []block.Lane{suite.mevLane},
Logger: suite.ctx.Logger(),
TxEncoder: suite.encodingConfig.TxConfig.TxEncoder(),
TxDecoder: suite.encodingConfig.TxConfig.TxDecoder(),
AnteHandler: suite.anteHandler,
SignerExtractor: signer_extraction.NewDefaultAdapter(),
MaxBlockSpace: math.LegacyZeroDec(),
IgnoreList: []block.Lane{suite.mevLane},
}
suite.baseLane = defaultlane.NewDefaultLane(baseConfig)