block-sdk/abci/abci_test.go
2024-06-25 10:48:18 -04:00

1464 lines
45 KiB
Go

package abci_test
import (
"context"
"math/rand"
"testing"
"cosmossdk.io/log"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
cometabci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
"github.com/skip-mev/block-sdk/v2/abci"
"github.com/skip-mev/block-sdk/v2/block"
"github.com/skip-mev/block-sdk/v2/lanes/free"
testutils "github.com/skip-mev/block-sdk/v2/testutils"
)
type ProposalsTestSuite struct {
suite.Suite
ctx sdk.Context
key *storetypes.KVStoreKey
encodingConfig testutils.EncodingConfig
random *rand.Rand
accounts []testutils.Account
gasTokenDenom string
}
func TestProposalsTestSuite(t *testing.T) {
suite.Run(t, new(ProposalsTestSuite))
}
func (s *ProposalsTestSuite) SetupTest() {
// Set up basic TX encoding config.
s.encodingConfig = testutils.CreateTestEncodingConfig()
// Create a few random accounts
s.random = rand.New(rand.NewSource(1))
s.accounts = testutils.RandomAccounts(s.random, 5)
s.gasTokenDenom = "stake"
s.key = storetypes.NewKVStoreKey("test")
testCtx := testutil.DefaultContextWithDB(s.T(), s.key, storetypes.NewTransientStoreKey("transient_test"))
s.ctx = testCtx.Ctx.WithIsCheckTx(true)
s.ctx = s.ctx.WithBlockHeight(1)
}
func (s *ProposalsTestSuite) SetupSubTest() {
s.setBlockParams(1000000000000, 1000000000000)
}
func (s *ProposalsTestSuite) TestPrepareProposal() {
s.Run("can prepare a proposal with no transactions", func() {
// Set up the default lane with no transactions
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("1"), nil)
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(0, len(resp.Txs))
})
s.Run("can build a proposal with a single tx from the lane", func() {
// Create a random transaction that will be inserted into the default lane
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Set up the default lane
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("1"), map[sdk.Tx]bool{tx: true})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NotNil(resp)
s.Require().NoError(err)
proposal := s.getTxBytes(tx)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal with multiple txs from the default lane", func() {
// Create a random transaction that will be inserted into the default lane
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
1,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Create a second random transaction that will be inserted into the default lane
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(200000000)),
)
s.Require().NoError(err)
// Set up the default lane with both transactions passing
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("1"), map[sdk.Tx]bool{tx1: true, tx2: true})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx1))
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx2))
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NotNil(resp)
s.Require().NoError(err)
proposal := s.getTxBytes(tx2, tx1)
s.Require().Equal(2, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal with single tx with other that fails", func() {
// Create a random transaction that will be inserted into the default lane
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Create a second random transaction that will be inserted into the default lane
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
1,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(200000000)),
)
s.Require().NoError(err)
// Set up the default lane with both transactions passing
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("1"), map[sdk.Tx]bool{tx1: true, tx2: false})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx1))
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx2))
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NotNil(resp)
s.Require().NoError(err)
proposal := s.getTxBytes(tx1)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal an empty proposal with multiple lanes", func() {
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), nil)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.5"), nil)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(0, len(resp.Txs))
})
s.Run("can build a proposal with transactions from a single lane given multiple lanes", func() {
// Create a bid tx that includes a single bundled tx
tx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[0:1],
100,
)
s.Require().NoError(err)
// Set up the TOB lane with the bid tx and the bundled tx
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
tx: true,
bundleTxs[0]: true,
})
s.Require().NoError(mevLane.Insert(sdk.Context{}, tx))
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.5"), nil)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(tx, bundleTxs[0])
s.Require().Equal(2, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can ignore txs that are already included in a proposal", func() {
// Create a bid tx that includes a single bundled tx
tx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[0:1],
100,
)
s.Require().NoError(err)
// Set up the TOB lane with the bid tx and the bundled tx
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
tx: true,
bundleTxs[0]: true,
})
s.Require().NoError(mevLane.Insert(sdk.Context{}, tx))
// Set up the default lane with the bid tx and the bundled tx
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
tx: true,
bundleTxs[0]: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
s.Require().NoError(defaultLane.Insert(sdk.Context{}, bundleTxs[0]))
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(tx, bundleTxs[0])
s.Require().Equal(2, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal where first lane has failing tx and second lane has a valid tx", func() {
// Create a bid tx that includes a single bundled tx
tx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[0:1],
100,
)
s.Require().NoError(err)
// Set up the TOB lane with the bid tx and the bundled tx
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
tx: false,
bundleTxs[0]: true,
})
s.Require().NoError(mevLane.Insert(sdk.Context{}, tx))
// Set up the default lane with the bid tx and the bundled tx
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0"), map[sdk.Tx]bool{
// Even though this passes it should not include it in the proposal because it is in the ignore list
tx: true,
bundleTxs[0]: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
s.Require().NoError(defaultLane.Insert(sdk.Context{}, bundleTxs[0]))
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(bundleTxs[0])
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal with single tx from middle lane", func() {
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), nil)
freeTx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
"test",
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
freeTx: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, freeTx))
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
freeTx: true,
})
s.Require().NoError(freeLane.Insert(sdk.Context{}, freeTx))
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).PrepareProposalHandler()
proposal := s.getTxBytes(freeTx)
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("transaction from every lane", func() {
// Create a bid tx that includes a single bundled tx
tx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[0:4],
100,
)
s.Require().NoError(err)
// Create a normal tx
normalTx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Create a free tx
freeTx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
0,
"test",
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
tx: true,
bundleTxs[0]: true,
bundleTxs[1]: true,
bundleTxs[2]: true,
bundleTxs[3]: true,
})
mevLane.Insert(sdk.Context{}, tx)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
normalTx: true,
})
defaultLane.Insert(sdk.Context{}, normalTx)
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
freeTx: true,
})
freeLane.Insert(sdk.Context{}, freeTx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).PrepareProposalHandler()
proposal := s.getTxBytes(tx, bundleTxs[0], bundleTxs[1], bundleTxs[2], bundleTxs[3], freeTx, normalTx)
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(7, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal where first lane does not have enough gas but second lane does", func() {
// set up the gas block limit for the proposal
s.setBlockParams(100, 1000000000)
// Create a bid tx that includes a single bundled tx
tx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[0:1],
51,
)
s.Require().NoError(err)
// Set up the TOB lane with the bid tx and the bundled tx
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
tx: true,
bundleTxs[0]: true,
})
s.Require().NoError(mevLane.Insert(sdk.Context{}, tx))
// create a random tx to be included in the default lane
normalTx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
0,
0,
100, // This should consume all of the block limit
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
normalTx: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, normalTx))
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
proposal := s.getTxBytes(tx, bundleTxs[0], normalTx)
// Should be theoretically sufficient to fit the bid tx and the bundled tx + normal tx
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal[2:], resp.Txs)
})
}
func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
s.Run("can build a proposal if a lane panics first", func() {
panicLane := s.setUpPanicLane("panik1", math.LegacyMustNewDecFromStr("0.25"))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
lanes := []block.Lane{
panicLane,
defaultLane,
}
mempool, err := block.NewLanedMempool(
log.NewNopLogger(),
lanes,
)
s.Require().NoError(err)
proposalHandler := abci.New(
log.NewNopLogger(),
s.encodingConfig.TxConfig.TxDecoder(),
s.encodingConfig.TxConfig.TxEncoder(),
mempool,
true,
).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(tx)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal if second lane panics", func() {
panicLane := s.setUpPanicLane("panik1", math.LegacyMustNewDecFromStr("0.25"))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
lanes := []block.Lane{
defaultLane,
panicLane,
}
mempool, err := block.NewLanedMempool(
log.NewNopLogger(),
lanes,
)
s.Require().NoError(err)
proposalHandler := abci.New(
log.NewNopLogger(),
s.encodingConfig.TxConfig.TxDecoder(),
s.encodingConfig.TxConfig.TxEncoder(),
mempool,
true,
).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(tx)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal if multiple consecutive lanes panic", func() {
panicLane := s.setUpPanicLane("panik1", math.LegacyMustNewDecFromStr("0.25"))
panicLane2 := s.setUpPanicLane("panik2", math.LegacyMustNewDecFromStr("0.25"))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
lanes := []block.Lane{
panicLane,
panicLane2,
defaultLane,
}
mempool, err := block.NewLanedMempool(
log.NewNopLogger(),
lanes,
)
s.Require().NoError(err)
proposalHandler := abci.New(
log.NewNopLogger(),
s.encodingConfig.TxConfig.TxDecoder(),
s.encodingConfig.TxConfig.TxEncoder(),
mempool,
true,
).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(tx)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
s.Run("can build a proposal if the last few lanes panic", func() {
panicLane := s.setUpPanicLane("panik1", math.LegacyMustNewDecFromStr("0.25"))
panicLane2 := s.setUpPanicLane("panik2", math.LegacyMustNewDecFromStr("0.25"))
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
lanes := []block.Lane{
defaultLane,
panicLane,
panicLane2,
}
mempool, err := block.NewLanedMempool(
log.NewNopLogger(),
lanes,
)
s.Require().NoError(err)
proposalHandler := abci.New(
log.NewNopLogger(),
s.encodingConfig.TxConfig.TxDecoder(),
s.encodingConfig.TxConfig.TxEncoder(),
mempool,
true,
).PrepareProposalHandler()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
proposal := s.getTxBytes(tx)
s.Require().Equal(1, len(resp.Txs))
s.Require().Equal(proposal, resp.Txs)
})
}
func (s *ProposalsTestSuite) TestProcessProposal() {
s.Run("can process a valid empty proposal", func() {
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{})
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{})
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{})
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).ProcessProposalHandler()
var proposal [][]byte
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 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,
})
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx1))
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx2))
var 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(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(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Mev lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{})
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
proposal := s.createProposal(tx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, 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 txs from multiple lanes", func() {
// Create a random transaction that will be inserted into the default lane
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// create a bid tx that will be inserted into the mev lane
bidTx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[1],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[1:2],
100,
)
s.Require().NoError(err)
// create a free tx that will be inserted into the free lane
freeTx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
0,
"test",
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Mev lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
bidTx: true,
bundleTxs[0]: true,
})
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
freeTx: true,
})
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
proposal := s.createProposal(bidTx, bundleTxs[0], freeTx, tx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, 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 reject a proposal with txs from multiple lanes", func() {
// Create a random transaction that will be inserted into the default lane
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// create a bid tx that will be inserted into the mev lane
bidTx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[1],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[1:2],
100,
)
s.Require().NoError(err)
// create a free tx that will be inserted into the free lane
freeTx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
0,
"test",
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Mev lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
bidTx: true,
bundleTxs[0]: true,
})
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
freeTx: true,
})
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
proposal := s.createProposal(bidTx, bundleTxs[0], tx, freeTx) // tx and freeTx are out of order
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().Error(err)
s.Require().NotNil(resp)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("can reject a proposal with txs from multiple lanes (mev is mixed up)", func() {
// Create a random transaction that will be inserted into the default lane
tx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// create a bid tx that will be inserted into the mev lane
bidTx, bundleTxs, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[1],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
0,
s.accounts[1:2],
100,
)
s.Require().NoError(err)
// create a free tx that will be inserted into the free lane
freeTx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
0,
"test",
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
)
s.Require().NoError(err)
// Mev lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
bidTx: true,
bundleTxs[0]: true,
})
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{
freeTx: true,
})
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{
tx: true,
})
proposal := s.createProposal(freeTx, tx, bidTx, bundleTxs[0])
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().Error(err)
s.Require().NotNil(resp)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("rejects a proposal with bad txs", func() {
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{})
freeLane := s.setUpFreeLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{})
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{})
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).ProcessProposalHandler()
proposal := [][]byte{{0x01, 0x02, 0x03}}
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("rejects a proposal when a lane panics", func() {
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.25"), map[sdk.Tx]bool{})
panicLane := s.setUpPanicLane("default", math.LegacyMustNewDecFromStr("0.0"))
txbz, err := testutils.CreateRandomTxBz(
s.encodingConfig.TxConfig,
s.accounts[0],
0,
0,
0,
1,
)
s.Require().NoError(err)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, panicLane}).ProcessProposalHandler()
proposal := [][]byte{txbz}
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("can process a invalid proposal (default lane out of order)", func() {
// Create a random transaction that will be inserted into the default lane
tx1, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2000000)),
)
s.Require().NoError(err)
// Create a random transaction that will be inserted into the default lane
tx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[2],
1,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2000000)),
)
s.Require().NoError(err)
// Mev lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.3"), map[sdk.Tx]bool{})
// Set up the default lane
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.0"), map[sdk.Tx]bool{tx2: true, tx1: true})
proposal := s.createProposal(tx2, tx1)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("can process a invalid proposal where first lane is valid second is not", func() {
bidTx, bundle, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
1,
s.accounts[0:2],
10,
)
s.Require().NoError(err)
normalTx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(3000000)),
)
s.Require().NoError(err)
normalTx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(3000000)),
)
s.Require().NoError(err)
// Set up the default lane
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
normalTx: true,
normalTx2: false,
})
// Set up the TOB lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
bidTx: true,
bundle[0]: true,
bundle[1]: true,
})
proposal := s.createProposal(bidTx, bundle[0], bundle[1], normalTx, normalTx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("can process a invalid proposal where a lane consumes too much gas", func() {
s.setBlockParams(1000, 10000000)
bidTx, _, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
1,
s.accounts[0:0],
10000000000, // This should consume too much gas for the lane
)
s.Require().NoError(err)
normalTx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(3000000)),
)
s.Require().NoError(err)
normalTx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2000000)),
)
s.Require().NoError(err)
// Set up the default lane
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0"), nil)
// Set up the TOB lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.1"), nil)
proposal := s.createProposal(bidTx, normalTx, normalTx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("can process a invalid proposal where a lane consumes too much block space", func() {
bidTx, _, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
1,
s.accounts[0:0],
1,
)
s.Require().NoError(err)
normalTx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(3000000)),
)
s.Require().NoError(err)
normalTx2, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2000000)),
)
s.Require().NoError(err)
proposalTxs := s.getTxBytes(bidTx, normalTx, normalTx2)
s.setBlockParams(1000, int64(len(proposalTxs[0])+len(proposalTxs[1])+len(proposalTxs[2])-1))
// Set up the default lane
defaultLane := s.setUpStandardLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
normalTx: true,
normalTx2: true,
})
// Set up the TOB lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
bidTx: true,
})
proposal := s.createProposal(bidTx, normalTx, normalTx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
s.Run("rejects a proposal where there are transactions remaining that have been unverified", func() {
bidTx, _, err := testutils.CreateAuctionTx(
s.encodingConfig.TxConfig,
s.accounts[0],
sdk.NewCoin(s.gasTokenDenom, math.NewInt(1000000)),
0,
1,
s.accounts[0:0],
1,
)
s.Require().NoError(err)
freeTx, err := testutils.CreateFreeTx(
s.encodingConfig.TxConfig,
s.accounts[2],
0,
1,
"test",
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2000000)),
sdk.NewCoin(s.gasTokenDenom, math.NewInt(2000000)),
)
s.Require().NoError(err)
normalTx, err := testutils.CreateRandomTx(
s.encodingConfig.TxConfig,
s.accounts[1],
0,
1,
0,
1,
sdk.NewCoin(s.gasTokenDenom, math.NewInt(3000000)),
)
s.Require().NoError(err)
// Set up the top of block lane
mevLane := s.setUpTOBLane(math.LegacyMustNewDecFromStr("0.5"), map[sdk.Tx]bool{
bidTx: true,
})
// Set up the default lane
freeLane := s.setUpCustomMatchHandlerLane(
math.LegacyMustNewDecFromStr("0.0"),
map[sdk.Tx]bool{
freeTx: true,
},
free.DefaultMatchHandler(),
"default",
)
proposal := s.createProposal(bidTx, freeTx, normalTx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
s.Require().Equal(&cometabci.ResponseProcessProposal{Status: cometabci.ResponseProcessProposal_REJECT}, resp)
})
}
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)
feeDenoms := []string{
s.gasTokenDenom,
"eth",
"btc",
"usdt",
"usdc",
}
// Create a bunch of transactions to insert into the default lane
txsToInsert := []sdk.Tx{}
validationMap := make(map[sdk.Tx]bool)
for nonce := uint64(0); nonce < numTxsPerAccount*uint64(numAccounts); nonce++ {
fees := []sdk.Coin{}
// choose a random set of fee denoms
perm := rand.Perm(len(feeDenoms))
for i := 0; i < 1+rand.Intn(len(feeDenoms)-1); i++ {
fees = append(fees, sdk.NewCoin(feeDenoms[perm[i]], math.NewInt(int64(rand.Intn(100000)))))
}
// choose a random set of accounts
perm = rand.Perm(len(accounts))
signers := []testutils.Account{}
for i := 0; i < 1+rand.Intn(len(accounts)-1); i++ {
signers = append(signers, accounts[perm[i]])
}
// create a random fee amount
tx, err := testutils.CreateRandomTxMultipleSigners(
s.encodingConfig.TxConfig,
signers,
nonce,
1,
0,
1,
fees...,
)
s.Require().NoError(err)
txsToInsert = append(txsToInsert, tx)
validationMap[tx] = true
}
// Set up the default lane with the transactions
defaultLane := s.setUpStandardLane(math.LegacyZeroDec(), validationMap)
for _, tx := range txsToInsert {
s.Require().NoError(defaultLane.Insert(s.ctx, tx))
}
// Create a bunch of transactions to insert into the free lane
var 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.25"), 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.
var 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.
var 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()
maxTxBytes := s.ctx.ConsensusParams().Block.MaxBytes
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2, MaxTxBytes: maxTxBytes})
s.Require().NoError(err)
s.Require().NotNil(resp)
// 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])
}
// 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+int(numTxsPerLane)])
}
proposal := s.createProposal(
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
var 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.LegacyZeroDec(), validationMap)
for _, tx := range txsToInsert {
s.Require().NoError(defaultLane.Insert(s.ctx, tx))
}
// Create a bunch of transactions to insert into the free lane
var 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.3"), 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.
var 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.
var 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(
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)
}