From 3abfde4f34404e85ca25361e8732ef740df3867c Mon Sep 17 00:00:00 2001 From: Nikhil Vasan <97126437+nivasan1@users.noreply.github.com> Date: Wed, 27 Sep 2023 08:08:10 -0700 Subject: [PATCH] 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 --- Makefile | 2 +- abci/abci_test.go | 47 ++- .../signer_extraction_adapter.go | 51 +++ .../signer_extraction_adapter_test.go | 53 +++ block/base/config.go | 21 +- block/base/mempool.go | 4 +- block/base/priority_nonce.go | 48 +-- block/mempool_test.go | 36 +- lanes/base/abci_test.go | 2 + lanes/base/lane.go | 1 + lanes/base/mempool_test.go | 9 +- lanes/free/lane.go | 1 + lanes/mev/check_tx.go | 26 +- lanes/mev/factory.go | 19 +- lanes/mev/lane.go | 1 + lanes/mev/mev_test.go | 3 +- tests/app/app.go | 36 +- tests/integration/block_sdk_suite.go | 379 ++++++++++++------ tests/integration/chain_setup.go | 174 ++++++-- tests/integration/go.mod | 7 +- tests/integration/go.sum | 13 +- x/auction/ante/ante.go | 15 +- x/auction/ante/ante_test.go | 27 +- 23 files changed, 675 insertions(+), 300 deletions(-) create mode 100644 adapters/signer_extraction_adapter/signer_extraction_adapter.go create mode 100644 adapters/signer_extraction_adapter/signer_extraction_adapter_test.go diff --git a/Makefile b/Makefile index 220b5d0..42f0b99 100644 --- a/Makefile +++ b/Makefile @@ -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/) diff --git a/abci/abci_test.go b/abci/abci_test.go index b12a9f9..1c26c00 100644 --- a/abci/abci_test.go +++ b/abci/abci_test.go @@ -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(), ) diff --git a/adapters/signer_extraction_adapter/signer_extraction_adapter.go b/adapters/signer_extraction_adapter/signer_extraction_adapter.go new file mode 100644 index 0000000..e905c5b --- /dev/null +++ b/adapters/signer_extraction_adapter/signer_extraction_adapter.go @@ -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 +} diff --git a/adapters/signer_extraction_adapter/signer_extraction_adapter_test.go b/adapters/signer_extraction_adapter/signer_extraction_adapter_test.go new file mode 100644 index 0000000..220db0b --- /dev/null +++ b/adapters/signer_extraction_adapter/signer_extraction_adapter_test.go @@ -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) +} diff --git a/block/base/config.go b/block/base/config.go index c273660..9275efe 100644 --- a/block/base/config.go +++ b/block/base/config.go @@ -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") } diff --git a/block/base/mempool.go b/block/base/mempool.go index a0d5d2f..2c39ac6 100644 --- a/block/base/mempool.go +++ b/block/base/mempool.go @@ -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, diff --git a/block/base/priority_nonce.go b/block/base/priority_nonce.go index 1b32019..21913fa 100644 --- a/block/base/priority_nonce.go +++ b/block/base/priority_nonce.go @@ -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} diff --git a/block/mempool_test.go b/block/mempool_test.go index 753379a..714bc27 100644 --- a/block/mempool_test.go +++ b/block/mempool_test.go @@ -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, diff --git a/lanes/base/abci_test.go b/lanes/base/abci_test.go index 242e3d5..c577fb6 100644 --- a/lanes/base/abci_test.go +++ b/lanes/base/abci_test.go @@ -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, ) diff --git a/lanes/base/lane.go b/lanes/base/lane.go index 8f2a1f9..eb8f38d 100644 --- a/lanes/base/lane.go +++ b/lanes/base/lane.go @@ -30,6 +30,7 @@ func NewDefaultLane(cfg base.LaneConfig) *DefaultLane { base.NewMempool[string]( base.DefaultTxPriority(), cfg.TxEncoder, + cfg.SignerExtractor, cfg.MaxTxs, ), base.DefaultMatchHandler(), diff --git a/lanes/base/mempool_test.go b/lanes/base/mempool_test.go index e66a8a3..c21120c 100644 --- a/lanes/base/mempool_test.go +++ b/lanes/base/mempool_test.go @@ -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, diff --git a/lanes/free/lane.go b/lanes/free/lane.go index a6e2b5d..ceabef7 100644 --- a/lanes/free/lane.go +++ b/lanes/free/lane.go @@ -33,6 +33,7 @@ func NewFreeLane( base.NewMempool[string]( txPriority, cfg.TxEncoder, + cfg.SignerExtractor, cfg.MaxTxs, ), matchFn, diff --git a/lanes/mev/check_tx.go b/lanes/mev/check_tx.go index 48c9a4a..e5807f4 100644 --- a/lanes/mev/check_tx.go +++ b/lanes/mev/check_tx.go @@ -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{ diff --git a/lanes/mev/factory.go b/lanes/mev/factory.go index 2009453..41cf6f1 100644 --- a/lanes/mev/factory.go +++ b/lanes/mev/factory.go @@ -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) diff --git a/lanes/mev/lane.go b/lanes/mev/lane.go index 55617d1..7b6d6da 100644 --- a/lanes/mev/lane.go +++ b/lanes/mev/lane.go @@ -53,6 +53,7 @@ func NewMEVLane( base.NewMempool[string]( TxPriority(factory), cfg.TxEncoder, + cfg.SignerExtractor, cfg.MaxTxs, ), factory.MatchHandler(), diff --git a/lanes/mev/mev_test.go b/lanes/mev/mev_test.go index 8485a63..4f6a2c5 100644 --- a/lanes/mev/mev_test.go +++ b/lanes/mev/mev_test.go @@ -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 diff --git a/tests/app/app.go b/tests/app/app.go index 4b2de6b..29a8039 100644 --- a/tests/app/app.go +++ b/tests/app/app.go @@ -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) diff --git a/tests/integration/block_sdk_suite.go b/tests/integration/block_sdk_suite.go index 6bae76d..88c278c 100644 --- a/tests/integration/block_sdk_suite.go +++ b/tests/integration/block_sdk_suite.go @@ -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}, diff --git a/tests/integration/chain_setup.go b/tests/integration/chain_setup.go index c13c95f..2fe1b64 100644 --- a/tests/integration/chain_setup.go +++ b/tests/integration/chain_setup.go @@ -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 +} diff --git a/tests/integration/go.mod b/tests/integration/go.mod index e233853..e5e5789 100644 --- a/tests/integration/go.mod +++ b/tests/integration/go.mod @@ -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 diff --git a/tests/integration/go.sum b/tests/integration/go.sum index a208be0..59cf040 100644 --- a/tests/integration/go.sum +++ b/tests/integration/go.sum @@ -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= diff --git a/x/auction/ante/ante.go b/x/auction/ante/ante.go index e5538f5..9526916 100644 --- a/x/auction/ante/ante.go +++ b/x/auction/ante/ante.go @@ -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 { diff --git a/x/auction/ante/ante_test.go b/x/auction/ante/ante_test.go index a35a868..0f07afb 100644 --- a/x/auction/ante/ante_test.go +++ b/x/auction/ante/ante_test.go @@ -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)