fix(compare): Adding Sequence Number check on Compare Priority (#159)

* adding seq num check on compare

* nit

* adding debug logging
This commit is contained in:
David Terpay 2023-10-17 16:50:28 -04:00 committed by GitHub
parent 339b927323
commit aff0e228a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 842 additions and 41 deletions

View File

@ -23,6 +23,8 @@
### 🤔 What is the Block SDK?
> **Note**: The Block SDK is midway through an audit. Please use at your own risk. Timeline for audit completion is early November.
**🌐 The Block SDK is a toolkit for building customized blocks**. The Block SDK is a set of Cosmos SDK and ABCI++ primitives that allow chains to fully customize blocks to specific use cases. It turns your chain's blocks into a **`highway`** consisting of individual **`lanes`** with their own special functionality.

View File

@ -75,7 +75,7 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
)
// Fill the proposal with transactions from each lane.
finalProposal, err := h.prepareLanesHandler(ctx, proposals.NewProposalWithContext(ctx, h.txEncoder))
finalProposal, err := h.prepareLanesHandler(ctx, proposals.NewProposalWithContext(h.logger, ctx, h.txEncoder))
if err != nil {
h.logger.Error("failed to prepare proposal", "err", err)
return &abci.ResponsePrepareProposal{Txs: make([][]byte, 0)}, err
@ -141,7 +141,7 @@ func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
// Build handler that will verify the partial proposals according to each lane's verification logic.
processLanesHandler := ChainProcessLanes(partialProposals, h.mempool.Registry())
finalProposal, err := processLanesHandler(ctx, proposals.NewProposalWithContext(ctx, h.txEncoder))
finalProposal, err := processLanesHandler(ctx, proposals.NewProposalWithContext(h.logger, ctx, h.txEncoder))
if err != nil {
h.logger.Error("failed to validate the proposal", "err", err)
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err

View File

@ -1,6 +1,7 @@
package abci_test
import (
"context"
"math/rand"
"testing"
@ -862,6 +863,54 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_ACCEPT}, resp)
})
s.Run("can accept proposal where txs are broadcasted with different sequence numbers", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx1: true,
tx2: true,
})
defaultLane.Insert(sdk.Context{}, tx1)
defaultLane.Insert(sdk.Context{}, tx2)
txs := [][]sdk.Tx{}
for iterator := defaultLane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
txs = append(txs, []sdk.Tx{iterator.Tx()})
}
s.Require().Equal(2, len(txs))
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 2}, tx1, tx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_ACCEPT}, resp)
})
s.Run("can process a valid proposal with a single tx", func() {
// Create a random transaction that will be inserted into the default lane
tx, err := testutils.CreateRandomTx(
@ -1271,6 +1320,227 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
})
}
func (s *ProposalsTestSuite) TestPrepareProcessParity() {
// Define a large enough block size and gas limit to ensure that the proposal is accepted
s.setBlockParams(1000000000000, 1000000000000)
// Create a random transaction that will be inserted into the default/free lane
numTxsPerAccount := uint64(25)
numAccounts := 25
accounts := testutils.RandomAccounts(s.random, numAccounts)
// Create a bunch of transactions to insert into the default lane
txsToInsert := []sdk.Tx{}
validationMap := make(map[sdk.Tx]bool)
for _, account := range accounts {
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
// create a random fee amount
feeAmount := math.NewInt(int64(rand.Intn(100000)))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
account,
nonce,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, feeAmount),
)
s.Require().NoError(err)
txsToInsert = append(txsToInsert, tx)
validationMap[tx] = true
}
}
// Set up the default lane with the transactions
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), validationMap)
for _, tx := range txsToInsert {
s.Require().NoError(defaultLane.Insert(s.ctx, tx))
}
// Create a bunch of transactions to insert into the free lane
freeTxsToInsert := []sdk.Tx{}
freeValidationMap := make(map[sdk.Tx]bool)
for _, account := range accounts {
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
// create a random fee amount
feeAmount := math.NewInt(int64(rand.Intn(100000)))
tx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
account,
nonce,
1,
"test",
sdk.NewCoin(s.gasTokenDenom, feeAmount),
sdk.NewCoin(s.gasTokenDenom, feeAmount),
)
s.Require().NoError(err)
freeTxsToInsert = append(freeTxsToInsert, tx)
freeValidationMap[tx] = true
}
}
freelane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.0"), freeValidationMap)
for _, tx := range freeTxsToInsert {
s.Require().NoError(freelane.Insert(s.ctx, tx))
}
// Retrieve the transactions from the default lane in the same way the prepare function would.
retrievedTxs := []sdk.Tx{}
for iterator := defaultLane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
retrievedTxs = append(retrievedTxs, iterator.Tx())
}
s.Require().Equal(len(txsToInsert), len(retrievedTxs))
// Retrieve the transactions from the free lane in the same way the prepare function would.
freeRetrievedTxs := []sdk.Tx{}
for iterator := freelane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
freeRetrievedTxs = append(freeRetrievedTxs, iterator.Tx())
}
s.Require().Equal(len(freeTxsToInsert), len(freeRetrievedTxs))
numTxsPerLane := numTxsPerAccount * uint64(numAccounts)
s.Require().Equal(numTxsPerLane, uint64(len(retrievedTxs)))
s.Require().Equal(numTxsPerLane, uint64(len(freeRetrievedTxs)))
// Create a proposal with the retrieved transactions
// Set up the default lane with no transactions
proposalHandler := s.setUpProposalHandlers([]block.Lane{freelane, defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
info := s.getProposalInfo(resp.Txs[0])
s.Require().NotNil(info)
s.Require().Equal(2, len(info.TxsByLane))
s.Require().Equal(numTxsPerLane, info.TxsByLane[defaultLane.Name()])
s.Require().Equal(numTxsPerLane, info.TxsByLane[freelane.Name()])
s.Require().Equal(numTxsPerLane*2, uint64(len(resp.Txs)-1))
// Ensure the transactions are in the correct order for the free lane
for i := 0; i < int(numTxsPerLane); i++ {
bz, err := s.encodingConfig.TxConfig.TxEncoder()(freeRetrievedTxs[i])
s.Require().NoError(err)
s.Require().Equal(bz, resp.Txs[i+1])
}
// Ensure the transactions are in the correct order for the default lane
for i := 0; i < int(numTxsPerLane); i++ {
bz, err := s.encodingConfig.TxConfig.TxEncoder()(retrievedTxs[i])
s.Require().NoError(err)
s.Require().Equal(bz, resp.Txs[i+1+int(numTxsPerLane)])
}
proposal := s.createProposal(
map[string]uint64{defaultLane.Name(): numTxsPerLane, freelane.Name(): numTxsPerLane},
append(freeRetrievedTxs, retrievedTxs...)...,
)
// Validate the proposal
processHandler := s.setUpProposalHandlers([]block.Lane{freelane, defaultLane}).ProcessProposalHandler()
processResp, err := processHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(processResp)
s.Require().NoError(err)
}
func (s *ProposalsTestSuite) TestIterateMempoolAndProcessProposalParity() {
// Define a large enough block size and gas limit to ensure that the proposal is accepted
s.setBlockParams(1000000000000, 1000000000000)
// Create a random transaction that will be inserted into the default/free lane
numTxsPerAccount := uint64(25)
numAccounts := 25
accounts := testutils.RandomAccounts(s.random, numAccounts)
// Create a bunch of transactions to insert into the default lane
txsToInsert := []sdk.Tx{}
validationMap := make(map[sdk.Tx]bool)
for _, account := range accounts {
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
// create a random fee amount
feeAmount := math.NewInt(int64(rand.Intn(100000)))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
account,
nonce,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, feeAmount),
)
s.Require().NoError(err)
txsToInsert = append(txsToInsert, tx)
validationMap[tx] = true
}
}
// Set up the default lane with the transactions
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), validationMap)
for _, tx := range txsToInsert {
s.Require().NoError(defaultLane.Insert(s.ctx, tx))
}
// Create a bunch of transactions to insert into the free lane
freeTxsToInsert := []sdk.Tx{}
freeValidationMap := make(map[sdk.Tx]bool)
for _, account := range accounts {
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
// create a random fee amount
feeAmount := math.NewInt(int64(rand.Intn(100000)))
tx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
account,
nonce,
1,
"test",
sdk.NewCoin(s.gasTokenDenom, feeAmount),
sdk.NewCoin(s.gasTokenDenom, feeAmount),
)
s.Require().NoError(err)
freeTxsToInsert = append(freeTxsToInsert, tx)
freeValidationMap[tx] = true
}
}
freelane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.0"), freeValidationMap)
for _, tx := range freeTxsToInsert {
s.Require().NoError(freelane.Insert(s.ctx, tx))
}
// Retrieve the transactions from the default lane in the same way the prepare function would.
retrievedTxs := []sdk.Tx{}
for iterator := defaultLane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
retrievedTxs = append(retrievedTxs, iterator.Tx())
}
s.Require().Equal(len(txsToInsert), len(retrievedTxs))
// Retrieve the transactions from the free lane in the same way the prepare function would.
freeRetrievedTxs := []sdk.Tx{}
for iterator := freelane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
freeRetrievedTxs = append(freeRetrievedTxs, iterator.Tx())
}
s.Require().Equal(len(freeTxsToInsert), len(freeRetrievedTxs))
// Create a proposal with the retrieved transactions
numTxsPerLane := numTxsPerAccount * uint64(numAccounts)
s.Require().Equal(numTxsPerLane, uint64(len(retrievedTxs)))
s.Require().Equal(numTxsPerLane, uint64(len(freeRetrievedTxs)))
proposal := s.createProposal(
map[string]uint64{defaultLane.Name(): numTxsPerLane, freelane.Name(): numTxsPerLane},
append(freeRetrievedTxs, retrievedTxs...)...,
)
// Validate the proposal
proposalHandler := s.setUpProposalHandlers([]block.Lane{freelane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().NoError(err)
}
func (s *ProposalsTestSuite) TestValidateBasic() {
// Set up the default lane with no transactions
mevlane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), nil)

View File

@ -124,8 +124,10 @@ func (l *BaseLane) DefaultProcessLaneHandler() ProcessLaneHandler {
// If the transactions do not respect the priority defined by the mempool, we consider the proposal
// to be invalid
if index > 0 && l.Compare(ctx, partialProposal[index-1], tx) == -1 {
return fmt.Errorf("transaction at index %d has a higher priority than %d", index, index-1)
if index > 0 {
if v, err := l.Compare(ctx, partialProposal[index-1], tx); v == -1 || err != nil {
return fmt.Errorf("transaction at index %d has a higher priority than %d", index, index-1)
}
}
if err := l.VerifyTx(ctx, tx, false); err != nil {

View File

@ -22,6 +22,10 @@ type (
// index defines an index of transactions.
index sdkmempool.Mempool
// signerExtractor defines the signer extraction adapter that allows us to
// extract the signer from a transaction.
extractor signer_extraction.Adapter
// txPriority defines the transaction priority function. It is used to
// retrieve the priority of a given transaction and to compare the priority
// of two transactions. The index utilizes this struct to order transactions
@ -91,6 +95,7 @@ func NewMempool[C comparable](txPriority TxPriority[C], txEncoder sdk.TxEncoder,
},
extractor,
),
extractor: extractor,
txPriority: txPriority,
txEncoder: txEncoder,
txCache: make(map[string]struct{}),
@ -155,8 +160,48 @@ func (cm *Mempool[C]) Contains(tx sdk.Tx) bool {
}
// Compare determines the relative priority of two transactions belonging in the same lane.
func (cm *Mempool[C]) Compare(ctx sdk.Context, this sdk.Tx, other sdk.Tx) int {
// There are two cases to consider:
// 1. The transactions have the same signer. In this case, we compare the sequence numbers.
// 2. The transactions have different signers. In this case, we compare the priorities of the
// transactions.
//
// Compare will return -1 if this transaction has a lower priority than the other transaction, 0 if
// they have the same priority, and 1 if this transaction has a higher priority than the other transaction.
func (cm *Mempool[C]) Compare(ctx sdk.Context, this sdk.Tx, other sdk.Tx) (int, error) {
signers, err := cm.extractor.GetSigners(this)
if err != nil {
return 0, err
}
if len(signers) == 0 {
return 0, fmt.Errorf("expected one signer for the first transaction")
}
// The priority nonce mempool uses the first tx signer so this is a safe operation.
thisSignerInfo := signers[0]
signers, err = cm.extractor.GetSigners(other)
if err != nil {
return 0, err
}
if len(signers) == 0 {
return 0, fmt.Errorf("expected one signer for the second transaction")
}
otherSignerInfo := signers[0]
// If the signers are the same, we compare the sequence numbers.
if thisSignerInfo.Signer.Equals(otherSignerInfo.Signer) {
switch {
case thisSignerInfo.Sequence < otherSignerInfo.Sequence:
return 1, nil
case thisSignerInfo.Sequence > otherSignerInfo.Sequence:
return -1, nil
default:
// This case should never happen but we add in the case for completeness.
return 0, fmt.Errorf("the two transactions have the same sequence number")
}
}
// Determine the priority and compare the priorities.
firstPriority := cm.txPriority.GetTxPriority(ctx, this)
secondPriority := cm.txPriority.GetTxPriority(ctx, other)
return cm.txPriority.Compare(firstPriority, secondPriority)
return cm.txPriority.Compare(firstPriority, secondPriority), nil
}

View File

@ -18,7 +18,7 @@ type LaneMempool interface {
// Compare determines the relative priority of two transactions belonging in the same lane. Compare
// will return -1 if this transaction has a lower priority than the other transaction, 0 if they have
// the same priority, and 1 if this transaction has a higher priority than the other transaction.
Compare(ctx sdk.Context, this, other sdk.Tx) int
Compare(ctx sdk.Context, this, other sdk.Tx) (int, error)
// Contains returns true if the transaction is contained in the mempool.
Contains(tx sdk.Tx) bool

View File

@ -1,6 +1,7 @@
package proposals
import (
"cosmossdk.io/log"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/block-sdk/block/proposals/types"
@ -9,6 +10,8 @@ import (
type (
// Proposal defines a block proposal type.
Proposal struct {
Logger log.Logger
// Txs is the list of transactions in the proposal.
Txs [][]byte
// Cache is a cache of the selected transactions in the proposal.
@ -21,15 +24,16 @@ type (
)
// NewProposalWithContext returns a new empty proposal.
func NewProposalWithContext(ctx sdk.Context, txEncoder sdk.TxEncoder) Proposal {
func NewProposalWithContext(logger log.Logger, ctx sdk.Context, txEncoder sdk.TxEncoder) Proposal {
maxBlockSize, maxGasLimit := GetBlockLimits(ctx)
return NewProposal(txEncoder, maxBlockSize, maxGasLimit)
return NewProposal(logger, txEncoder, maxBlockSize, maxGasLimit)
}
// NewProposal returns a new empty proposal. Any transactions added to the proposal
// will be subject to the given max block size and max gas limit.
func NewProposal(txEncoder sdk.TxEncoder, maxBlockSize int64, maxGasLimit uint64) Proposal {
func NewProposal(logger log.Logger, txEncoder sdk.TxEncoder, maxBlockSize int64, maxGasLimit uint64) Proposal {
return Proposal{
Logger: logger,
TxEncoder: txEncoder,
Txs: make([][]byte, 0),
Cache: make(map[string]struct{}),

View File

@ -4,6 +4,7 @@ import (
"math/rand"
"testing"
"cosmossdk.io/log"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/block-sdk/block/mocks"
@ -27,7 +28,7 @@ func TestUpdateProposal(t *testing.T) {
lane.On("GetMaxBlockSpace").Return(math.LegacyNewDec(1)).Maybe()
t.Run("can update with no transactions", func(t *testing.T) {
proposal := proposals.NewProposal(nil, 100, 100)
proposal := proposals.NewProposal(log.NewTestLogger(t), nil, 100, 100)
err := proposal.UpdateProposal(lane, nil)
require.NoError(t, err)
@ -59,7 +60,7 @@ func TestUpdateProposal(t *testing.T) {
size := len(txBzs[0])
gasLimit := 100
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
err = proposal.UpdateProposal(lane, []sdk.Tx{tx})
require.NoError(t, err)
@ -105,7 +106,7 @@ func TestUpdateProposal(t *testing.T) {
gasLimit += 100
}
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size), gasLimit)
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), gasLimit)
err = proposal.UpdateProposal(lane, txs)
require.NoError(t, err)
@ -142,7 +143,7 @@ func TestUpdateProposal(t *testing.T) {
size := int64(len(txBzs[0]))
gasLimit := uint64(100)
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), size, gasLimit)
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), size, gasLimit)
err = proposal.UpdateProposal(lane, []sdk.Tx{tx})
require.NoError(t, err)
@ -202,7 +203,7 @@ func TestUpdateProposal(t *testing.T) {
size := len(txBzs[0]) + len(txBzs[1])
gasLimit := 200
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
err = proposal.UpdateProposal(lane, []sdk.Tx{tx})
require.NoError(t, err)
@ -240,7 +241,7 @@ func TestUpdateProposal(t *testing.T) {
size := len(txBzs[0])
gasLimit := 100
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
lane := mocks.NewLane(t)
@ -278,7 +279,7 @@ func TestUpdateProposal(t *testing.T) {
size := len(txBzs[0])
gasLimit := 100
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit))
lane := mocks.NewLane(t)
@ -316,7 +317,7 @@ func TestUpdateProposal(t *testing.T) {
size := len(txBzs[0])
gasLimit := 100
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size)-1, uint64(gasLimit))
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size)-1, uint64(gasLimit))
err = proposal.UpdateProposal(lane, []sdk.Tx{tx})
require.Error(t, err)
@ -349,7 +350,7 @@ func TestUpdateProposal(t *testing.T) {
size := len(txBzs[0])
gasLimit := 100
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)-1)
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), int64(size), uint64(gasLimit)-1)
err = proposal.UpdateProposal(lane, []sdk.Tx{tx})
require.Error(t, err)
@ -390,7 +391,7 @@ func TestUpdateProposal(t *testing.T) {
txBzs, err := utils.GetEncodedTxs(encodingConfig.TxConfig.TxEncoder(), []sdk.Tx{tx, tx2})
require.NoError(t, err)
proposal := proposals.NewProposal(encodingConfig.TxConfig.TxEncoder(), 10000, 10000)
proposal := proposals.NewProposal(log.NewTestLogger(t), encodingConfig.TxConfig.TxEncoder(), 10000, 10000)
err = proposal.UpdateProposal(lane, []sdk.Tx{tx})
require.NoError(t, err)

View File

@ -1,6 +1,7 @@
package proposals
import (
"encoding/base64"
"fmt"
"cosmossdk.io/math"
@ -46,6 +47,17 @@ func (p *Proposal) UpdateProposal(lane Lane, partialProposal []sdk.Tx) error {
return fmt.Errorf("err retrieving transaction info: %s", err)
}
p.Logger.Debug(
"updating proposal with tx",
"index", index,
"lane", lane.Name(),
"tx_hash", txInfo.Hash,
"tx_size", txInfo.Size,
"tx_gas_limit", txInfo.GasLimit,
"tx_bytes", txInfo.TxBytes,
"raw_tx", base64.StdEncoding.EncodeToString(txInfo.TxBytes),
)
// invariant check: Ensure that the transaction is not already in the proposal.
if _, ok := p.Cache[txInfo.Hash]; ok {
return fmt.Errorf("transaction %s is already in the proposal", txInfo.Hash)

View File

@ -1,9 +1,11 @@
package base_test
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/rand"
"cosmossdk.io/log"
"cosmossdk.io/math"
@ -43,6 +45,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
int64(len(txBz)),
1,
@ -86,6 +89,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
MaxGasLimit: 10,
}
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
limit.MaxTxBytes,
limit.MaxGasLimit,
@ -130,6 +134,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
MaxGasLimit: 10,
}
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
limit.MaxTxBytes,
limit.MaxGasLimit,
@ -173,6 +178,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
MaxGasLimit: 10,
}
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
limit.MaxTxBytes,
limit.MaxGasLimit,
@ -213,6 +219,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
int64(len(txBz)),
10,
@ -272,6 +279,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
size := int64(len(txBz1)) + int64(len(txBz2))
gasLimit := uint64(20)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
size,
gasLimit,
@ -328,6 +336,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
size := int64(len(txBz1)) + int64(len(txBz2))
gasLimit := uint64(2)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
size,
gasLimit,
@ -387,6 +396,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
size := int64(len(txBz1)) + int64(len(txBz2)) - 1
gasLimit := uint64(3)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
size,
gasLimit,
@ -446,6 +456,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
size := int64(len(txBz1)) + int64(len(txBz2)) - 1
gasLimit := uint64(1)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
size,
gasLimit,
@ -487,6 +498,7 @@ func (s *BaseTestSuite) TestPrepareLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
int64(len(txBz))*10,
1000000,
@ -512,6 +524,195 @@ func (s *BaseTestSuite) TestPrepareLane() {
}
func (s *BaseTestSuite) TestProcessLane() {
s.Run("should accept a proposal where transaction fees are not in order bc of sequence numbers", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2)),
)
s.Require().NoError(err)
proposal := []sdk.Tx{
tx1,
tx2, // This transaction has a higher sequence number and higher fees
}
lane := s.initLane(
math.LegacyOneDec(),
map[sdk.Tx]bool{
tx1: true,
tx2: true,
},
)
partialProposal, err := utils.GetEncodedTxs(s.encodingConfig.TxConfig.TxEncoder(), proposal)
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
)
_, err = lane.ProcessLane(s.ctx, emptyProposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
})
s.Run("should accept a proposal where transaction fees are not in order bc of sequence numbers with other txs", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(10)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(20)),
)
s.Require().NoError(err)
tx3, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(3)),
)
s.Require().NoError(err)
proposal := []sdk.Tx{
tx1,
tx2, // This transaction has a higher sequence number and higher fees
tx3,
}
lane := s.initLane(
math.LegacyOneDec(),
map[sdk.Tx]bool{
tx1: true,
tx2: true,
tx3: true,
},
)
partialProposal, err := utils.GetEncodedTxs(s.encodingConfig.TxConfig.TxEncoder(), proposal)
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
)
_, err = lane.ProcessLane(s.ctx, emptyProposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
})
s.Run("accepts proposal with multiple senders and seq nums", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(10)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(20)),
)
s.Require().NoError(err)
tx3, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(9)),
)
s.Require().NoError(err)
tx4, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
1,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(11)),
)
s.Require().NoError(err)
proposal := []sdk.Tx{
tx1,
tx2,
tx3,
tx4,
}
lane := s.initLane(
math.LegacyOneDec(),
map[sdk.Tx]bool{
tx1: true,
tx2: true,
tx3: true,
tx4: true,
},
)
partialProposal, err := utils.GetEncodedTxs(s.encodingConfig.TxConfig.TxEncoder(), proposal)
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
)
_, err = lane.ProcessLane(s.ctx, emptyProposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
})
s.Run("should accept a proposal with valid transactions", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
@ -538,6 +739,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
@ -573,6 +775,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
@ -631,6 +834,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
@ -679,6 +883,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
@ -727,6 +932,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
@ -778,6 +984,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
100000,
100000,
@ -813,6 +1020,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
maxSize,
1000000,
@ -849,6 +1057,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
maxSize,
9,
@ -896,6 +1105,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
maxSize,
19,
@ -944,6 +1154,7 @@ func (s *BaseTestSuite) TestProcessLane() {
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
maxSize,
20,
@ -954,6 +1165,146 @@ func (s *BaseTestSuite) TestProcessLane() {
})
}
func (s *BaseTestSuite) TestPrepareProcessParity() {
txsToInsert := []sdk.Tx{}
validationMap := make(map[sdk.Tx]bool)
numTxsPerAccount := uint64(50)
accounts := testutils.RandomAccounts(s.random, 50)
for _, account := range accounts {
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
// create a random fee amount
feeAmount := math.NewInt(int64(rand.Intn(100000)))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
account,
nonce,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, feeAmount),
)
s.Require().NoError(err)
txsToInsert = append(txsToInsert, tx)
validationMap[tx] = true
}
}
// Add the transactions to the lane
lane := s.initLane(math.LegacyOneDec(), validationMap)
for _, tx := range txsToInsert {
s.Require().NoError(lane.Insert(s.ctx, tx))
}
// Retrieve the transactions from the lane in the same way the prepare function would.
retrievedTxs := []sdk.Tx{}
for iterator := lane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
retrievedTxs = append(retrievedTxs, iterator.Tx())
}
s.Require().Equal(len(txsToInsert), len(retrievedTxs))
// Construct a block proposal with the transactions in the mempool
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
1000000000000000,
1000000000000000,
)
proposal, err := lane.PrepareLane(s.ctx, emptyProposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
s.Require().Equal(len(txsToInsert), len(proposal.Txs))
// Ensure that the transactions are in the same order
for i := 0; i < len(retrievedTxs); i++ {
bz, err := s.encodingConfig.TxConfig.TxEncoder()(retrievedTxs[i])
s.Require().NoError(err)
s.Require().Equal(bz, proposal.Txs[i])
}
// Verify the same proposal with the process lanes handler
emptyProposal = proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
1000000000000000,
1000000000000000,
)
proposal, err = lane.ProcessLane(s.ctx, emptyProposal, proposal.Txs, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
s.Require().Equal(len(txsToInsert), len(proposal.Txs))
s.T().Logf("proposal num txs: %d", len(proposal.Txs))
// Ensure that the transactions are in the same order
for i := 0; i < len(retrievedTxs); i++ {
bz, err := s.encodingConfig.TxConfig.TxEncoder()(retrievedTxs[i])
s.Require().NoError(err)
s.Require().Equal(bz, proposal.Txs[i])
}
}
func (s *BaseTestSuite) TestIterateMempoolAndProcessProposalParity() {
txsToInsert := []sdk.Tx{}
validationMap := make(map[sdk.Tx]bool)
numTxsPerAccount := uint64(200)
accounts := testutils.RandomAccounts(s.random, 50)
for _, account := range accounts {
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
// create a random fee amount
feeAmount := math.NewInt(int64(rand.Intn(100000)))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
account,
nonce,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, feeAmount),
)
s.Require().NoError(err)
txsToInsert = append(txsToInsert, tx)
validationMap[tx] = true
}
}
// Add the transactions to the lane
lane := s.initLane(math.LegacyOneDec(), validationMap)
for _, tx := range txsToInsert {
s.Require().NoError(lane.Insert(s.ctx, tx))
}
// Retrieve the transactions from the lane in the same way the prepare function would.
retrievedTxs := []sdk.Tx{}
for iterator := lane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
retrievedTxs = append(retrievedTxs, iterator.Tx())
}
s.Require().Equal(len(txsToInsert), len(retrievedTxs))
partialProposal, err := utils.GetEncodedTxs(s.encodingConfig.TxConfig.TxEncoder(), retrievedTxs)
s.Require().NoError(err)
emptyProposal := proposals.NewProposal(
log.NewTestLogger(s.T()),
s.encodingConfig.TxConfig.TxEncoder(),
1000000000000000,
1000000000000000,
)
proposal, err := lane.ProcessLane(s.ctx, emptyProposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
s.Require().Equal(len(txsToInsert), len(proposal.Txs))
s.T().Logf("proposal num txs: %d", len(proposal.Txs))
// Ensure that the transactions are in the same order
for i := 0; i < len(retrievedTxs); i++ {
bz, err := s.encodingConfig.TxConfig.TxEncoder()(retrievedTxs[i])
s.Require().NoError(err)
s.Require().Equal(bz, proposal.Txs[i])
}
}
func (s *BaseTestSuite) initLane(
maxBlockSpace math.LegacyDec,
expectedExecution map[sdk.Tx]bool,

View File

@ -86,6 +86,119 @@ func (s *BaseTestSuite) TestCompareTxPriority() {
b := sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)).String()
s.Require().Equal(0, txPriority.Compare(a, b))
})
lane := s.initLane(math.LegacyOneDec(), nil)
s.Run("should return -1 when signers are the same but the first tx has a higher sequence", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
cmp, err := lane.Compare(sdk.Context{}, tx1, tx2)
s.Require().NoError(err)
s.Require().Equal(-1, cmp)
})
s.Run("should return 1 when signers are the same but the second tx has a higher sequence", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
cmp, err := lane.Compare(sdk.Context{}, tx1, tx2)
s.Require().NoError(err)
s.Require().Equal(1, cmp)
})
s.Run("should return 0 when signers are the same and the sequence is the same", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
_, err = lane.Compare(sdk.Context{}, tx1, tx2)
s.Require().Error(err)
})
s.Run("should return 1 when the first tx has a higher priority", func() {
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(200)),
)
s.Require().NoError(err)
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
0,
0,
0,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(100)),
)
s.Require().NoError(err)
cmp, err := lane.Compare(sdk.Context{}, tx1, tx2)
s.Require().NoError(err)
s.Require().Equal(1, cmp)
})
}
func (s *BaseTestSuite) TestInsert() {

View File

@ -1,6 +1,7 @@
package mev_test
import (
log "cosmossdk.io/log"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/block-sdk/block"
@ -14,7 +15,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
s.Run("can prepare a lane with no txs in mempool", func() {
lane := s.initLane(math.LegacyOneDec(), nil)
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal, err := lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -40,7 +41,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true})
s.Require().NoError(lane.Insert(s.ctx, bidTx))
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -82,7 +83,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
s.Require().NoError(lane.Insert(s.ctx, bidTx1))
s.Require().NoError(lane.Insert(s.ctx, bidTx2))
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 20000, 100000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 100000)
proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -124,7 +125,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
s.Require().NoError(lane.Insert(s.ctx, bidTx1))
s.Require().NoError(lane.Insert(s.ctx, bidTx2))
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 20000, 100000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 100000)
proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -154,7 +155,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true})
s.Require().NoError(lane.Insert(s.ctx, bidTx))
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 20000, 100000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 100000)
proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -185,7 +186,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true})
s.Require().NoError(lane.Insert(s.ctx, bidTx))
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), s.getTxSize(bidTx), 100000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), s.getTxSize(bidTx), 100000)
proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -210,7 +211,7 @@ func (s *MEVTestSuite) TestPrepareLane() {
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true})
s.Require().NoError(lane.Insert(s.ctx, bidTx))
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), s.getTxSize(bidTx), 99)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), s.getTxSize(bidTx), 99)
proposal, err = lane.PrepareLane(s.ctx, proposal, block.NoOpPrepareLanesHandler())
s.Require().NoError(err)
@ -226,7 +227,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Run("can process an empty proposal", func() {
lane := s.initLane(math.LegacyOneDec(), nil)
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal, err := lane.ProcessLane(s.ctx, proposal, nil, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
@ -241,7 +242,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), nil)
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100)
_, err = lane.ProcessLane(s.ctx, proposal, [][]byte{txBz}, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -263,7 +264,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: false})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -285,7 +286,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: false})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -307,7 +308,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -329,7 +330,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -351,7 +352,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
@ -373,7 +374,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200000, 1000000)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().NoError(err)
@ -395,7 +396,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 20000, 99)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 20000, 99)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -417,7 +418,7 @@ func (s *MEVTestSuite) TestProcessLane() {
s.Require().NoError(err)
lane := s.initLane(math.LegacyOneDec(), map[sdk.Tx]bool{bidTx: true, bundle[0]: true, bundle[1]: true})
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100)
_, err = lane.ProcessLane(s.ctx, proposal, partialProposal, block.NoOpProcessLanesHandler())
s.Require().Error(err)
@ -426,7 +427,7 @@ func (s *MEVTestSuite) TestProcessLane() {
func (s *MEVTestSuite) TestVerifyBidBasic() {
lane := s.initLane(math.LegacyOneDec(), nil)
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), 200, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), 200, 100)
limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace())
s.Run("can verify a bid with no bundled txs", func() {
@ -490,7 +491,7 @@ func (s *MEVTestSuite) TestVerifyBidBasic() {
s.Require().NoError(err)
size := s.getTxSize(bidTx)
proposal := proposals.NewProposal(s.encCfg.TxConfig.TxEncoder(), size-1, 100)
proposal := proposals.NewProposal(log.NewTestLogger(s.T()), s.encCfg.TxConfig.TxEncoder(), size-1, 100)
limits := proposal.GetLaneLimits(lane.GetMaxBlockSpace())
_, err = lane.VerifyBidBasic(bidTx, proposal, limits)

View File

@ -102,6 +102,6 @@ func (t Terminator) Select(context.Context, [][]byte) sdkmempool.Iterator {
}
// HasHigherPriority is a no-op
func (t Terminator) Compare(sdk.Context, sdk.Tx, sdk.Tx) int {
return 0
func (t Terminator) Compare(sdk.Context, sdk.Tx, sdk.Tx) (int, error) {
return 0, nil
}