[ENG-702]: Caching context when iterating through auctions (#56)

This commit is contained in:
David Terpay 2023-04-12 15:31:21 -04:00 committed by GitHub
parent acaf60e5b8
commit 06812560fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 63 deletions

View File

@ -9,33 +9,32 @@ import (
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/libs/log"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkmempool "github.com/cosmos/cosmos-sdk/types/mempool"
"github.com/skip-mev/pob/mempool"
)
type ProposalHandler struct {
mempool *mempool.AuctionMempool
logger log.Logger
txVerifier baseapp.ProposalTxVerifier
txEncoder sdk.TxEncoder
txDecoder sdk.TxDecoder
mempool *mempool.AuctionMempool
logger log.Logger
anteHandler sdk.AnteHandler
txEncoder sdk.TxEncoder
txDecoder sdk.TxDecoder
}
func NewProposalHandler(
mp *mempool.AuctionMempool,
logger log.Logger,
txVerifier baseapp.ProposalTxVerifier,
anteHandler sdk.AnteHandler,
txEncoder sdk.TxEncoder,
txDecoder sdk.TxDecoder,
) *ProposalHandler {
return &ProposalHandler{
mempool: mp,
logger: logger,
txVerifier: txVerifier,
txEncoder: txEncoder,
txDecoder: txDecoder,
mempool: mp,
logger: logger,
anteHandler: anteHandler,
txEncoder: txEncoder,
txDecoder: txDecoder,
}
}
@ -56,9 +55,10 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
// bundled transactions are valid.
selectBidTxLoop:
for ; bidTxIterator != nil; bidTxIterator = bidTxIterator.Next() {
cacheCtx, write := ctx.CacheContext()
tmpBidTx := bidTxIterator.Tx()
bidTxBz, err := h.txVerifier.PrepareProposalVerifyTx(tmpBidTx)
bidTxBz, err := h.PrepareProposalVerifyTx(cacheCtx, tmpBidTx)
if err != nil {
txsToRemove[tmpBidTx] = struct{}{}
continue selectBidTxLoop
@ -84,7 +84,7 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
continue selectBidTxLoop
}
if _, err := h.txVerifier.PrepareProposalVerifyTx(refTx); err != nil {
if _, err := h.PrepareProposalVerifyTx(cacheCtx, refTx); err != nil {
// Invalid bundled transaction, so we remove the bid transaction
// and try the next top bid.
txsToRemove[tmpBidTx] = struct{}{}
@ -106,6 +106,10 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
seenTxs[txHash] = struct{}{}
}
// Write the cache context to the original context when we know we have a
// valid top of block bundle.
write()
break selectBidTxLoop
}
@ -144,7 +148,7 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
continue selectTxLoop
}
txBz, err = h.txVerifier.PrepareProposalVerifyTx(memTx)
txBz, err = h.PrepareProposalVerifyTx(ctx, memTx)
if err != nil {
txsToRemove[memTx] = struct{}{}
continue selectTxLoop
@ -174,7 +178,7 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
return func(ctx sdk.Context, req abci.RequestProcessProposal) abci.ResponseProcessProposal {
for index, txBz := range req.Txs {
tx, err := h.txVerifier.ProcessProposalVerifyTx(txBz)
tx, err := h.ProcessProposalVerifyTx(ctx, txBz)
if err != nil {
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}
}
@ -208,6 +212,36 @@ func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
}
}
// PrepareProposalVerifyTx encodes a transaction and verifies it.
func (h *ProposalHandler) PrepareProposalVerifyTx(ctx sdk.Context, tx sdk.Tx) ([]byte, error) {
txBz, err := h.txEncoder(tx)
if err != nil {
return nil, err
}
return txBz, h.verifyTx(ctx, tx)
}
// ProcessProposalVerifyTx decodes a transaction and verifies it.
func (h *ProposalHandler) ProcessProposalVerifyTx(ctx sdk.Context, txBz []byte) (sdk.Tx, error) {
tx, err := h.txDecoder(txBz)
if err != nil {
return nil, err
}
return tx, h.verifyTx(ctx, tx)
}
// VerifyTx verifies a transaction against the application's state.
func (h *ProposalHandler) verifyTx(ctx sdk.Context, tx sdk.Tx) error {
if h.anteHandler != nil {
_, err := h.anteHandler(ctx, tx, false)
return err
}
return nil
}
func (h *ProposalHandler) RemoveTx(tx sdk.Tx) {
if err := h.mempool.RemoveWithoutRefTx(tx); err != nil && !errors.Is(err, sdkmempool.ErrTxNotFound) {
panic(fmt.Errorf("failed to remove invalid transaction from the mempool: %w", err))

View File

@ -107,60 +107,37 @@ func (suite *ABCITestSuite) SetupTest() {
// Proposal handler set up
suite.logger = log.NewNopLogger()
suite.proposalHandler = abci.NewProposalHandler(suite.mempool, suite.logger, suite, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder())
suite.proposalHandler = abci.NewProposalHandler(suite.mempool, suite.logger, suite.anteHandler, suite.encodingConfig.TxConfig.TxEncoder(), suite.encodingConfig.TxConfig.TxDecoder())
}
func (suite *ABCITestSuite) PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) {
_, err := suite.executeAnteHandler(tx)
if err != nil {
return nil, err
}
txBz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx)
if err != nil {
return nil, err
}
hash := sha256.Sum256(txBz)
txHash := hex.EncodeToString(hash[:])
if _, ok := suite.txs[txHash]; ok {
return nil, fmt.Errorf("tx already in mempool")
}
suite.txs[txHash] = struct{}{}
return txBz, nil
}
func (suite *ABCITestSuite) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) {
tx, err := suite.encodingConfig.TxConfig.TxDecoder()(txBz)
if err != nil {
return nil, err
}
_, err = suite.executeAnteHandler(tx)
if err != nil {
return tx, err
}
hash := sha256.Sum256(txBz)
txHash := hex.EncodeToString(hash[:])
if _, ok := suite.txs[txHash]; ok {
return nil, fmt.Errorf("tx already in mempool")
}
suite.txs[txHash] = struct{}{}
return tx, nil
}
func (suite *ABCITestSuite) executeAnteHandler(tx sdk.Tx) (sdk.Context, error) {
func (suite *ABCITestSuite) anteHandler(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
signer := tx.GetMsgs()[0].GetSigners()[0]
suite.bankKeeper.EXPECT().GetAllBalances(suite.ctx, signer).AnyTimes().Return(suite.balances)
suite.bankKeeper.EXPECT().GetAllBalances(ctx, signer).AnyTimes().Return(suite.balances)
next := func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
return ctx, nil
}
return suite.builderDecorator.AnteHandle(suite.ctx, tx, false, next)
ctx, err := suite.builderDecorator.AnteHandle(ctx, tx, false, next)
if err != nil {
return ctx, err
}
bz, err := suite.encodingConfig.TxConfig.TxEncoder()(tx)
if err != nil {
return ctx, err
}
if !simulate {
hash := sha256.Sum256(bz)
txHash := hex.EncodeToString(hash[:])
if _, ok := suite.txs[txHash]; ok {
return ctx, fmt.Errorf("tx already in mempool")
}
suite.txs[txHash] = struct{}{}
}
return ctx, nil
}
func (suite *ABCITestSuite) createFilledMempool(numNormalTxs, numAuctionTxs, numBundledTxs int, insertRefTxs bool) int {
@ -790,6 +767,6 @@ func (suite *ABCITestSuite) isTopBidValid() bool {
}
// check if the top bid is valid
_, err := suite.executeAnteHandler(iterator.Tx())
_, err := suite.anteHandler(suite.ctx, iterator.Tx(), true)
return err == nil
}