Skip to content
This repository was archived by the owner on Jan 31, 2025. It is now read-only.

Commit 863649c

Browse files
feat: Lane Options (backport #272) (#273)
* feat: Lane Options (#272) * init * lint * update mock * cr * readme nit (cherry picked from commit db58154) # Conflicts: # block/base/lane.go # block/mempool_test.go # block/mocks/lane.go * merge nit --------- Co-authored-by: David Terpay <35130517+davidterpay@users.noreply.github.com> Co-authored-by: David Terpay <david.terpay@gmail.com>
1 parent ea5748f commit 863649c

File tree

20 files changed

+377
-279
lines changed

20 files changed

+377
-279
lines changed

abci/abci_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package abci_test
33
import (
44
"context"
55
"math/rand"
6-
"os"
76
"testing"
87

98
"cosmossdk.io/math"
@@ -531,7 +530,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
531530
s.Require().NoError(err)
532531

533532
proposalHandler := abci.NewProposalHandler(
534-
log.NewTMLogger(os.Stdout),
533+
log.NewNopLogger(),
535534
s.encodingConfig.TxConfig.TxDecoder(),
536535
s.encodingConfig.TxConfig.TxEncoder(),
537536
mempool,
@@ -577,7 +576,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
577576
s.Require().NoError(err)
578577

579578
proposalHandler := abci.NewProposalHandler(
580-
log.NewTMLogger(os.Stdout),
579+
log.NewNopLogger(),
581580
s.encodingConfig.TxConfig.TxDecoder(),
582581
s.encodingConfig.TxConfig.TxEncoder(),
583582
mempool,
@@ -625,7 +624,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
625624
s.Require().NoError(err)
626625

627626
proposalHandler := abci.NewProposalHandler(
628-
log.NewTMLogger(os.Stdout),
627+
log.NewNopLogger(),
629628
s.encodingConfig.TxConfig.TxDecoder(),
630629
s.encodingConfig.TxConfig.TxEncoder(),
631630
mempool,
@@ -673,7 +672,7 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
673672
s.Require().NoError(err)
674673

675674
proposalHandler := abci.NewProposalHandler(
676-
log.NewTMLogger(os.Stdout),
675+
log.NewNopLogger(),
677676
s.encodingConfig.TxConfig.TxDecoder(),
678677
s.encodingConfig.TxConfig.TxEncoder(),
679678
mempool,

abci/utils_test.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,22 @@ func (s *ProposalsTestSuite) setUpCustomMatchHandlerLane(maxBlockSpace math.Lega
6363
SignerExtractor: signeradaptors.NewDefaultAdapter(),
6464
}
6565

66-
lane := base.NewBaseLane(
66+
options := []base.LaneOption{
67+
base.WithMatchHandler(mh),
68+
base.WithMempoolConfigs[string](cfg, base.DefaultTxPriority()),
69+
}
70+
71+
lane, err := base.NewBaseLane(
6772
cfg,
6873
name,
69-
base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, cfg.SignerExtractor, 0),
70-
mh,
74+
options...,
7175
)
72-
73-
lane.SetPrepareLaneHandler(lane.DefaultPrepareLaneHandler())
74-
lane.SetProcessLaneHandler(lane.DefaultProcessLaneHandler())
76+
s.Require().NoError(err)
7577

7678
return lane
7779
}
7880

79-
func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *defaultlane.DefaultLane {
81+
func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *base.BaseLane {
8082
cfg := base.LaneConfig{
8183
Logger: log.NewNopLogger(),
8284
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
@@ -103,7 +105,7 @@ func (s *ProposalsTestSuite) setUpTOBLane(maxBlockSpace math.LegacyDec, expected
103105
return mev.NewMEVLane(cfg, factory, factory.MatchHandler())
104106
}
105107

106-
func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *free.FreeLane {
108+
func (s *ProposalsTestSuite) setUpFreeLane(maxBlockSpace math.LegacyDec, expectedExecution map[sdk.Tx]bool) *base.BaseLane {
107109
cfg := base.LaneConfig{
108110
Logger: log.NewNopLogger(),
109111
TxEncoder: s.encodingConfig.TxConfig.TxEncoder(),
@@ -125,15 +127,19 @@ func (s *ProposalsTestSuite) setUpPanicLane(name string, maxBlockSpace math.Lega
125127
SignerExtractor: signeradaptors.NewDefaultAdapter(),
126128
}
127129

128-
lane := base.NewBaseLane(
130+
options := []base.LaneOption{
131+
base.WithMatchHandler(base.DefaultMatchHandler()),
132+
base.WithMempoolConfigs[string](cfg, base.DefaultTxPriority()),
133+
base.WithPrepareLaneHandler(base.PanicPrepareLaneHandler()),
134+
base.WithProcessLaneHandler(base.PanicProcessLaneHandler()),
135+
}
136+
137+
lane, err := base.NewBaseLane(
129138
cfg,
130139
name,
131-
base.NewMempool[string](base.DefaultTxPriority(), cfg.TxEncoder, cfg.SignerExtractor, 0),
132-
base.DefaultMatchHandler(),
140+
options...,
133141
)
134-
135-
lane.SetPrepareLaneHandler(base.PanicPrepareLaneHandler())
136-
lane.SetProcessLaneHandler(base.PanicProcessLaneHandler())
142+
s.Require().NoError(err)
137143

138144
return lane
139145
}

block/README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ type Lane interface {
7171
// Name returns the name of the lane.
7272
Name() string
7373

74-
// SetAnteHandler sets the lane's antehandler.
75-
SetAnteHandler(antehander sdk.AnteHandler)
76-
7774
// Match determines if a transaction belongs to this lane.
7875
Match(ctx sdk.Context, tx sdk.Tx) bool
7976

block/base/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func DefaultMatchHandler() base.MatchHandler {
4444
}
4545
```
4646

47-
The default `MatchHandler` is implemented in the [base lane](./handlers.go) and matches all transactions.
47+
The default `MatchHandler` is implemented in the [base lane](./match.go) and matches all transactions.
4848

4949
## PrepareLaneHandler
5050

@@ -60,7 +60,7 @@ PrepareLaneHandler func(
6060

6161
To create a custom lane with a custom `PrepareLaneHandler`, you must implement this function and set it on the lane after it has been created. Please visit the [MEV lane's](../../lanes/mev/abci.go) `PrepareLaneHandler` for an example of how to implement this function.
6262

63-
The default `PrepareLaneHandler` is implemented in the [base lane](./handlers.go). It reaps transactions from the mempool, validates them, ensures that the lane's block space limit is not exceeded, and returns the transactions to be included in the block and the ones that need to be removed.
63+
The default `PrepareLaneHandler` is implemented in the [base lane](./proposals.go). It reaps transactions from the mempool, validates them, ensures that the lane's block space limit is not exceeded, and returns the transactions to be included in the block and the ones that need to be removed.
6464

6565
## ProcessLaneHandler
6666

@@ -74,7 +74,7 @@ ProcessLaneHandler func(ctx sdk.Context, partialProposal []sdk.Tx) (
7474
)
7575
```
7676

77-
Note that block proposals built using the Block SDK contain contiguous sections of transactions in the block that belong to a given lane, to read more about how proposals are constructed relative to other lanes, please visit the [abci section](../../abci/README.md). As such, a given lane will recieve some transactions in (partialProposal) that belong to it and some that do not. The transactions that belong to it must be contiguous from the start, and the transactions that do not belong to it must be contiguous from the end. The lane must return the transactions that belong to it and the transactions that do not belong to it. The transactions that do not belong to it will be passed to the next lane in the proposal. The default `ProcessLaneHandler` is implemented in the [base lane](./handlers.go). It verifies the transactions that belong to the lane and returns them alongside the transactions that do not belong to the lane.
77+
Note that block proposals built using the Block SDK contain contiguous sections of transactions in the block that belong to a given lane, to read more about how proposals are constructed relative to other lanes, please visit the [abci section](../../abci/README.md). As such, a given lane will recieve some transactions in (partialProposal) that belong to it and some that do not. The transactions that belong to it must be contiguous from the start, and the transactions that do not belong to it must be contiguous from the end. The lane must return the transactions that belong to it and the transactions that do not belong to it. The transactions that do not belong to it will be passed to the next lane in the proposal. The default `ProcessLaneHandler` is implemented in the [base lane](./proposals.go). It verifies the transactions that belong to the lane and returns them alongside the transactions that do not belong to the lane.
7878

7979
Please visit the [MEV lane's](../../lanes/mev/abci.go) `ProcessLaneHandler` for an example of how to implement a custom handler.
8080

block/base/lane.go

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,35 @@ type BaseLane struct { //nolint
5050
func NewBaseLane(
5151
cfg LaneConfig,
5252
laneName string,
53-
laneMempool block.LaneMempool,
54-
matchHandlerFn MatchHandler,
55-
) *BaseLane {
53+
options ...LaneOption,
54+
) (*BaseLane, error) {
5655
lane := &BaseLane{
57-
cfg: cfg,
58-
laneName: laneName,
59-
LaneMempool: laneMempool,
60-
matchHandler: matchHandlerFn,
56+
cfg: cfg,
57+
laneName: laneName,
6158
}
6259

63-
return lane
60+
lane.LaneMempool = NewMempool(
61+
DefaultTxPriority(),
62+
lane.cfg.TxEncoder,
63+
lane.cfg.SignerExtractor,
64+
lane.cfg.MaxTxs,
65+
)
66+
67+
lane.matchHandler = DefaultMatchHandler()
68+
69+
handler := NewDefaultProposalHandler(lane)
70+
lane.prepareLaneHandler = handler.PrepareLaneHandler()
71+
lane.processLaneHandler = handler.ProcessLaneHandler()
72+
73+
for _, option := range options {
74+
option(lane)
75+
}
76+
77+
if err := lane.ValidateBasic(); err != nil {
78+
return nil, err
79+
}
80+
81+
return lane, nil
6482
}
6583

6684
// ValidateBasic ensures that the lane was constructed properly. In the case that
@@ -83,39 +101,16 @@ func (l *BaseLane) ValidateBasic() error {
83101
}
84102

85103
if l.prepareLaneHandler == nil {
86-
l.prepareLaneHandler = l.DefaultPrepareLaneHandler()
104+
return fmt.Errorf("prepare lane handler cannot be nil")
87105
}
88106

89107
if l.processLaneHandler == nil {
90-
l.processLaneHandler = l.DefaultProcessLaneHandler()
108+
return fmt.Errorf("process lane handler cannot be nil")
91109
}
92110

93111
return nil
94112
}
95113

96-
// SetPrepareLaneHandler sets the prepare lane handler for the lane. This handler
97-
// is called when a new proposal is being requested and the lane needs to submit
98-
// transactions it wants included in the block.
99-
func (l *BaseLane) SetPrepareLaneHandler(prepareLaneHandler PrepareLaneHandler) {
100-
if prepareLaneHandler == nil {
101-
panic("prepare lane handler cannot be nil")
102-
}
103-
104-
l.prepareLaneHandler = prepareLaneHandler
105-
}
106-
107-
// SetProcessLaneHandler sets the process lane handler for the lane. This handler
108-
// is called when a new proposal is being verified and the lane needs to verify
109-
// that the transactions included in the proposal are valid respecting the verification
110-
// logic of the lane.
111-
func (l *BaseLane) SetProcessLaneHandler(processLaneHandler ProcessLaneHandler) {
112-
if processLaneHandler == nil {
113-
panic("process lane handler cannot be nil")
114-
}
115-
116-
l.processLaneHandler = processLaneHandler
117-
}
118-
119114
// Match returns true if the transaction should be processed by this lane. This
120115
// function first determines if the transaction matches the lane and then checks
121116
// if the transaction is on the ignore list. If the transaction is on the ignore
@@ -129,11 +124,6 @@ func (l *BaseLane) Name() string {
129124
return l.laneName
130125
}
131126

132-
// SetAnteHandler sets the ante handler for the lane.
133-
func (l *BaseLane) SetAnteHandler(anteHandler sdk.AnteHandler) {
134-
l.cfg.AnteHandler = anteHandler
135-
}
136-
137127
// Logger returns the logger for the lane.
138128
func (l *BaseLane) Logger() log.Logger {
139129
return l.cfg.Logger
@@ -154,3 +144,12 @@ func (l *BaseLane) TxEncoder() sdk.TxEncoder {
154144
func (l *BaseLane) GetMaxBlockSpace() math.LegacyDec {
155145
return l.cfg.MaxBlockSpace
156146
}
147+
148+
// WithOptions returns a new lane with the given options.
149+
func (l *BaseLane) WithOptions(options ...LaneOption) *BaseLane {
150+
for _, option := range options {
151+
option(l)
152+
}
153+
154+
return l
155+
}

block/base/match.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package base
2+
3+
import (
4+
"fmt"
5+
6+
sdk "github.com/cosmos/cosmos-sdk/types"
7+
)
8+
9+
// DefaultMatchHandler returns a default implementation of the MatchHandler. It matches all
10+
// transactions.
11+
func DefaultMatchHandler() MatchHandler {
12+
return func(ctx sdk.Context, tx sdk.Tx) bool {
13+
return true
14+
}
15+
}
16+
17+
// VerifyNoMatches returns an error if any of the transactions match the lane.
18+
func (l *BaseLane) VerifyNoMatches(ctx sdk.Context, txs []sdk.Tx) error {
19+
for _, tx := range txs {
20+
if l.Match(ctx, tx) {
21+
return fmt.Errorf("transaction belongs to lane when it should not")
22+
}
23+
}
24+
25+
return nil
26+
}
27+
28+
// NewMatchHandler returns a match handler that matches transactions
29+
// that match the lane and do not match with any of the provided match handlers.
30+
// In the context of building an application, you would want to use this to
31+
// ignore the match handlers of other lanes in the application.
32+
func NewMatchHandler(mh MatchHandler, ignoreMHs ...MatchHandler) MatchHandler {
33+
return func(ctx sdk.Context, tx sdk.Tx) bool {
34+
for _, ignoreMH := range ignoreMHs {
35+
if ignoreMH(ctx, tx) {
36+
return false
37+
}
38+
}
39+
40+
return mh(ctx, tx)
41+
}
42+
}

block/base/options.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package base
2+
3+
import (
4+
sdk "github.com/cosmos/cosmos-sdk/types"
5+
"github.com/skip-mev/block-sdk/block"
6+
)
7+
8+
// LaneOption defines a function that can be used to set options on a lane.
9+
type LaneOption func(*BaseLane)
10+
11+
// WithAnteHandler sets the ante handler for the lane.
12+
func WithAnteHandler(anteHandler sdk.AnteHandler) LaneOption {
13+
return func(l *BaseLane) { l.cfg.AnteHandler = anteHandler }
14+
}
15+
16+
// WithPrepareLaneHandler sets the prepare lane handler for the lane. This handler
17+
// is called when a new proposal is being requested and the lane needs to submit
18+
// transactions it wants included in the block.
19+
func WithPrepareLaneHandler(prepareLaneHandler PrepareLaneHandler) LaneOption {
20+
return func(l *BaseLane) {
21+
if prepareLaneHandler == nil {
22+
panic("prepare lane handler cannot be nil")
23+
}
24+
25+
l.prepareLaneHandler = prepareLaneHandler
26+
}
27+
}
28+
29+
// WithProcessLaneHandler sets the process lane handler for the lane. This handler
30+
// is called when a new proposal is being verified and the lane needs to verify
31+
// that the transactions included in the proposal are valid respecting the verification
32+
// logic of the lane.
33+
func WithProcessLaneHandler(processLaneHandler ProcessLaneHandler) LaneOption {
34+
return func(l *BaseLane) {
35+
if processLaneHandler == nil {
36+
panic("process lane handler cannot be nil")
37+
}
38+
39+
l.processLaneHandler = processLaneHandler
40+
}
41+
}
42+
43+
// WithMatchHandler sets the match handler for the lane. This handler is called
44+
// when a new transaction is being submitted to the lane and the lane needs to
45+
// determine if the transaction should be processed by the lane.
46+
func WithMatchHandler(matchHandler MatchHandler) LaneOption {
47+
return func(l *BaseLane) {
48+
if matchHandler == nil {
49+
panic("match handler cannot be nil")
50+
}
51+
52+
l.matchHandler = matchHandler
53+
}
54+
}
55+
56+
// WithMempool sets the mempool for the lane. This mempool is used to store
57+
// transactions that are waiting to be processed.
58+
func WithMempool(mempool block.LaneMempool) LaneOption {
59+
return func(l *BaseLane) {
60+
if mempool == nil {
61+
panic("mempool cannot be nil")
62+
}
63+
64+
l.LaneMempool = mempool
65+
}
66+
}
67+
68+
// WithMempoolConfigs sets the mempool for the lane with the given lane config
69+
// and TxPriority struct. This mempool is used to store transactions that are waiting
70+
// to be processed.
71+
func WithMempoolConfigs[C comparable](cfg LaneConfig, txPriority TxPriority[C]) LaneOption {
72+
return func(l *BaseLane) {
73+
l.LaneMempool = NewMempool(
74+
txPriority,
75+
cfg.TxEncoder,
76+
cfg.SignerExtractor,
77+
cfg.MaxTxs,
78+
)
79+
}
80+
}

0 commit comments

Comments
 (0)