chore(verifytx): Updating VerifyTx to Cache between Transactions (#137)

* updating mev lane with cleaner impl

* nit

* lint

* updating anteverifytx to verify tx

* nit

* ignoring first height

* tidy
This commit is contained in:
David Terpay
2023-10-04 22:36:07 -04:00
committed by GitHub
parent cb9376e2f3
commit cbc0483e9f
12 changed files with 220 additions and 180 deletions
+24 -108
View File
@@ -9,7 +9,6 @@ import (
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/proposals"
"github.com/skip-mev/block-sdk/block/proposals/types"
)
const (
@@ -54,6 +53,10 @@ func NewProposalHandler(
// valid transactions in the proposal (up to MaxBlockSize, MaxGasLimit).
func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
return func(ctx sdk.Context, req *abci.RequestPrepareProposal) (resp *abci.ResponsePrepareProposal, err error) {
if req.Height <= 1 {
return &abci.ResponsePrepareProposal{Txs: req.Txs}, nil
}
// In the case where there is a panic, we recover here and return an empty proposal.
defer func() {
if rec := recover(); rec != nil {
@@ -65,14 +68,14 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
}
}()
h.logger.Info("mempool distribution before proposal creation", "distribution", h.mempool.GetTxDistribution())
// Build an empty placeholder proposal with the maximum block size and gas limit.
maxBlockSize, maxGasLimit := proposals.GetBlockLimits(ctx)
emptyProposal := proposals.NewProposal(h.txEncoder, maxBlockSize, maxGasLimit)
h.logger.Info(
"mempool distribution before proposal creation",
"distribution", h.mempool.GetTxDistribution(),
"height", req.Height,
)
// Fill the proposal with transactions from each lane.
finalProposal, err := h.prepareLanesHandler(ctx, emptyProposal)
finalProposal, err := h.prepareLanesHandler(ctx, proposals.NewProposalWithContext(ctx, h.txEncoder))
if err != nil {
h.logger.Error("failed to prepare proposal", "err", err)
return &abci.ResponsePrepareProposal{Txs: make([][]byte, 0)}, err
@@ -89,13 +92,17 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
"prepared proposal",
"num_txs", len(txs),
"total_tx_bytes", finalProposal.Info.BlockSize,
"max_tx_bytes", maxBlockSize,
"max_tx_bytes", finalProposal.Info.MaxBlockSize,
"total_gas_limit", finalProposal.Info.GasLimit,
"max_gas_limit", maxGasLimit,
"max_gas_limit", finalProposal.Info.MaxGasLimit,
"height", req.Height,
)
h.logger.Info("mempool distribution after proposal creation", "distribution", h.mempool.GetTxDistribution())
h.logger.Info(
"mempool distribution after proposal creation",
"distribution", h.mempool.GetTxDistribution(),
"height", req.Height,
)
return &abci.ResponsePrepareProposal{
Txs: txs,
@@ -111,6 +118,10 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
// transactions, then the proposal is rejected.
func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
return func(ctx sdk.Context, req *abci.RequestProcessProposal) (resp *abci.ResponseProcessProposal, err error) {
if req.Height <= 1 {
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
}
// In the case where any of the lanes panic, we recover here and return a reject status.
defer func() {
if rec := recover(); rec != nil {
@@ -130,13 +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())
// Build an empty placeholder proposal.
maxBlockSize, maxGasLimit := proposals.GetBlockLimits(ctx)
emptyProposal := proposals.NewProposal(h.txEncoder, maxBlockSize, maxGasLimit)
// Verify the proposal according to the verification logic from each lane.
finalProposal, err := processLanesHandler(ctx, emptyProposal)
finalProposal, err := processLanesHandler(ctx, proposals.NewProposalWithContext(ctx, h.txEncoder))
if err != nil {
h.logger.Error("failed to validate the proposal", "err", err)
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err
@@ -152,101 +157,12 @@ func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
"processed proposal",
"num_txs", len(req.Txs),
"total_tx_bytes", finalProposal.Info.BlockSize,
"max_tx_bytes", maxBlockSize,
"max_tx_bytes", finalProposal.Info.MaxBlockSize,
"total_gas_limit", finalProposal.Info.GasLimit,
"max_gas_limit", maxGasLimit,
"max_gas_limit", finalProposal.Info.MaxGasLimit,
"height", req.Height,
)
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
}
}
// ExtractLanes validates the proposal against the basic invariants that are required
// for the proposal to be valid. This includes:
// 1. The proposal must contain the proposal information and must be valid.
// 2. The proposal must contain the correct number of transactions for each lane.
func (h *ProposalHandler) ExtractLanes(proposal [][]byte) (types.ProposalInfo, [][][]byte, error) {
// If the proposal is empty, then the metadata was not included.
if len(proposal) == 0 {
return types.ProposalInfo{}, nil, fmt.Errorf("proposal does not contain proposal metadata")
}
metaDataBz, txs := proposal[ProposalInfoIndex], proposal[ProposalInfoIndex+1:]
// Retrieve the metadata from the proposal.
var metaData types.ProposalInfo
if err := metaData.Unmarshal(metaDataBz); err != nil {
return types.ProposalInfo{}, nil, fmt.Errorf("failed to unmarshal proposal metadata: %w", err)
}
lanes := h.mempool.Registry()
partialProposals := make([][][]byte, len(lanes))
if metaData.TxsByLane == nil {
if len(txs) > 0 {
return types.ProposalInfo{}, nil, fmt.Errorf("proposal contains invalid number of transactions")
}
return types.ProposalInfo{}, partialProposals, nil
}
h.logger.Info(
"received proposal with metadata",
"max_block_size", metaData.MaxBlockSize,
"max_gas_limit", metaData.MaxGasLimit,
"gas_limit", metaData.GasLimit,
"block_size", metaData.BlockSize,
"lanes_with_txs", metaData.TxsByLane,
)
// Iterate through all of the lanes and match the corresponding transactions to the lane.
for index, lane := range lanes {
numTxs := metaData.TxsByLane[lane.Name()]
if numTxs > uint64(len(txs)) {
return types.ProposalInfo{}, nil, fmt.Errorf(
"proposal metadata contains invalid number of transactions for lane %s; got %d, expected %d",
lane.Name(),
len(txs),
numTxs,
)
}
partialProposals[index] = txs[:numTxs]
txs = txs[numTxs:]
}
// If there are any transactions remaining in the proposal, then the proposal is invalid.
if len(txs) > 0 {
return types.ProposalInfo{}, nil, fmt.Errorf("proposal contains invalid number of transactions")
}
return metaData, partialProposals, nil
}
// ValidateBlockLimits validates the block limits of the proposal against the block limits
// of the chain.
func (h *ProposalHandler) ValidateBlockLimits(finalProposal proposals.Proposal, proposalInfo types.ProposalInfo) error {
// Conduct final checks on block size and gas limit.
if finalProposal.Info.BlockSize != proposalInfo.BlockSize {
h.logger.Error(
"proposal block size does not match",
"expected", proposalInfo.BlockSize,
"got", finalProposal.Info.BlockSize,
)
return fmt.Errorf("proposal block size does not match")
}
if finalProposal.Info.GasLimit != proposalInfo.GasLimit {
h.logger.Error(
"proposal gas limit does not match",
"expected", proposalInfo.GasLimit,
"got", finalProposal.Info.GasLimit,
)
return fmt.Errorf("proposal gas limit does not match")
}
return nil
}
+28 -27
View File
@@ -45,6 +45,7 @@ func (s *ProposalsTestSuite) SetupTest() {
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() {
@@ -58,7 +59,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
s.Require().Equal(1, len(resp.Txs))
@@ -93,7 +94,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NotNil(resp)
s.Require().NoError(err)
@@ -145,7 +146,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx2))
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NotNil(resp)
s.Require().NoError(err)
@@ -197,7 +198,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx2))
proposalHandler := s.setUpProposalHandlers([]block.Lane{defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NotNil(resp)
s.Require().NoError(err)
@@ -224,7 +225,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -266,7 +267,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -317,7 +318,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -369,7 +370,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -424,7 +425,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
size := int64(len(proposal[0]) - 1)
s.setBlockParams(10000000, size)
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -472,7 +473,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposal := s.getTxBytes(freeTx)
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -551,7 +552,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).PrepareProposalHandler()
proposal := s.getTxBytes(tx, bundleTxs[0], bundleTxs[1], bundleTxs[2], bundleTxs[3], freeTx, normalTx)
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -617,7 +618,7 @@ func (s *ProposalsTestSuite) TestPrepareProposal() {
proposal := s.getTxBytes(tx, bundleTxs[0], normalTx)
// Should be theoretically sufficient to fit the bid tx and the bundled tx + normal tx
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -667,7 +668,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
mempool,
).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -716,7 +717,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
mempool,
).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -766,7 +767,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
mempool,
).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -816,7 +817,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
mempool,
).PrepareProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{})
resp, err := proposalHandler(s.ctx, &cometabci.RequestPrepareProposal{Height: 2})
s.Require().NoError(err)
s.Require().NotNil(resp)
@@ -855,7 +856,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
)
proposal := [][]byte{info}
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
@@ -883,7 +884,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 1}, tx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
@@ -941,7 +942,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 1, mevLane.Name(): 2, freeLane.Name(): 1}, bidTx, bundleTxs[0], freeTx, tx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, freeLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
@@ -974,7 +975,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal[0] = infoBz
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
})
@@ -1006,7 +1007,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal[0] = infoBz
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
})
@@ -1031,7 +1032,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
)
proposal := [][]byte{info, {0x01, 0x02, 0x03}}
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
})
@@ -1063,7 +1064,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
)
proposal := [][]byte{info, txbz}
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
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)
})
@@ -1102,7 +1103,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 1, mevLane.Name(): 1}, tx2, tx)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
})
@@ -1157,7 +1158,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 2, mevLane.Name(): 3}, bidTx, bundle[0], bundle[1], normalTx, normalTx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
})
@@ -1207,7 +1208,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 2, mevLane.Name(): 1}, bidTx, normalTx, normalTx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
})
@@ -1264,7 +1265,7 @@ func (s *ProposalsTestSuite) TestProcessProposal() {
proposal := s.createProposal(map[string]uint64{defaultLane.Name(): 2, mevLane.Name(): 1}, bidTx, normalTx, normalTx2)
proposalHandler := s.setUpProposalHandlers([]block.Lane{mevLane, defaultLane}).ProcessProposalHandler()
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal})
resp, err := proposalHandler(s.ctx, &cometabci.RequestProcessProposal{Txs: proposal, Height: 2})
s.Require().NotNil(resp)
s.Require().Error(err)
})
+93 -1
View File
@@ -1,15 +1,107 @@
package abci
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/proposals"
"github.com/skip-mev/block-sdk/block/proposals/types"
"github.com/skip-mev/block-sdk/lanes/terminator"
)
// ExtractLanes validates the proposal against the basic invariants that are required
// for the proposal to be valid. This includes:
// 1. The proposal must contain the proposal information and must be valid.
// 2. The proposal must contain the correct number of transactions for each lane.
func (h *ProposalHandler) ExtractLanes(proposal [][]byte) (types.ProposalInfo, [][][]byte, error) {
// If the proposal is empty, then the metadata was not included.
if len(proposal) == 0 {
return types.ProposalInfo{}, nil, fmt.Errorf("proposal does not contain proposal metadata")
}
metaDataBz, txs := proposal[ProposalInfoIndex], proposal[ProposalInfoIndex+1:]
// Retrieve the metadata from the proposal.
var metaData types.ProposalInfo
if err := metaData.Unmarshal(metaDataBz); err != nil {
return types.ProposalInfo{}, nil, fmt.Errorf("failed to unmarshal proposal metadata: %w", err)
}
lanes := h.mempool.Registry()
partialProposals := make([][][]byte, len(lanes))
if metaData.TxsByLane == nil {
if len(txs) > 0 {
return types.ProposalInfo{}, nil, fmt.Errorf("proposal contains invalid number of transactions")
}
return types.ProposalInfo{}, partialProposals, nil
}
h.logger.Info(
"received proposal with metadata",
"max_block_size", metaData.MaxBlockSize,
"max_gas_limit", metaData.MaxGasLimit,
"gas_limit", metaData.GasLimit,
"block_size", metaData.BlockSize,
"lanes_with_txs", metaData.TxsByLane,
)
// Iterate through all of the lanes and match the corresponding transactions to the lane.
for index, lane := range lanes {
numTxs := metaData.TxsByLane[lane.Name()]
if numTxs > uint64(len(txs)) {
return types.ProposalInfo{}, nil, fmt.Errorf(
"proposal metadata contains invalid number of transactions for lane %s; got %d, expected %d",
lane.Name(),
len(txs),
numTxs,
)
}
partialProposals[index] = txs[:numTxs]
txs = txs[numTxs:]
}
// If there are any transactions remaining in the proposal, then the proposal is invalid.
if len(txs) > 0 {
return types.ProposalInfo{}, nil, fmt.Errorf("proposal contains invalid number of transactions")
}
return metaData, partialProposals, nil
}
// ValidateBlockLimits validates the block limits of the proposal against the block limits
// of the chain.
func (h *ProposalHandler) ValidateBlockLimits(finalProposal proposals.Proposal, proposalInfo types.ProposalInfo) error {
// Conduct final checks on block size and gas limit.
if finalProposal.Info.BlockSize != proposalInfo.BlockSize {
h.logger.Error(
"proposal block size does not match",
"expected", proposalInfo.BlockSize,
"got", finalProposal.Info.BlockSize,
)
return fmt.Errorf("proposal block size does not match")
}
if finalProposal.Info.GasLimit != proposalInfo.GasLimit {
h.logger.Error(
"proposal gas limit does not match",
"expected", proposalInfo.GasLimit,
"got", finalProposal.Info.GasLimit,
)
return fmt.Errorf("proposal gas limit does not match")
}
return nil
}
// ChainPrepareLanes chains together the proposal preparation logic from each lane into a
// single function. The first lane in the chain is the first lane to be prepared and the
// last lane in the chain is the last lane to be prepared.In the case where any of the lanes
// last lane in the chain is the last lane to be prepared. In the case where any of the lanes
// fail to prepare the partial proposal, the lane that failed will be skipped and the next
// lane in the chain will be called to prepare the proposal.
func ChainPrepareLanes(chain []block.Lane) block.PrepareLanesHandler {