feat: x/blocksdk module integration (#201)
* module proto * lane proto * proto-gen * proto-format * regenerate * genesis * stub * test * comment * new keeper functions * finalize * lint fix * proto format * encounteredLanes * make protos * generate * generate * msgs * msgs test * msg service * grpc query * add module * add module assertions * add client * config * app * clean * wip * mocks * integrate into mempool * lane utils * wip * fix and test * format * debug logs * add * integrate * format * fix * rm * add * fmt imports * better error * simplify * simplify * simplify * format * deep copy * Update block/lane.go Co-authored-by: Keefer Taylor | Tessellated <keefer@tessellated.io> --------- Co-authored-by: aljo242 <alex@ingenuity.build> Co-authored-by: Keefer Taylor | Tessellated <keefer@tessellated.io>
This commit is contained in:
co-authored by
Keefer Taylor | Tessellated
aljo242
parent
f5457e3e54
commit
41e85e9cfe
+25
-13
@@ -20,11 +20,10 @@ type (
|
||||
// ProposalHandler is a wrapper around the ABCI++ PrepareProposal and ProcessProposal
|
||||
// handlers.
|
||||
ProposalHandler struct {
|
||||
logger log.Logger
|
||||
txDecoder sdk.TxDecoder
|
||||
txEncoder sdk.TxEncoder
|
||||
prepareLanesHandler block.PrepareLanesHandler
|
||||
mempool block.Mempool
|
||||
logger log.Logger
|
||||
txDecoder sdk.TxDecoder
|
||||
txEncoder sdk.TxEncoder
|
||||
mempool block.Mempool
|
||||
}
|
||||
)
|
||||
|
||||
@@ -37,11 +36,10 @@ func NewProposalHandler(
|
||||
mempool block.Mempool,
|
||||
) *ProposalHandler {
|
||||
return &ProposalHandler{
|
||||
logger: logger,
|
||||
txDecoder: txDecoder,
|
||||
txEncoder: txEncoder,
|
||||
prepareLanesHandler: ChainPrepareLanes(mempool.Registry()),
|
||||
mempool: mempool,
|
||||
logger: logger,
|
||||
txDecoder: txDecoder,
|
||||
txEncoder: txEncoder,
|
||||
mempool: mempool,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +72,16 @@ func (h *ProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHandler {
|
||||
"height", req.Height,
|
||||
)
|
||||
|
||||
registry, err := h.mempool.Registry(ctx)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to get lane registry", "err", err)
|
||||
return &abci.ResponsePrepareProposal{Txs: make([][]byte, 0)}, err
|
||||
}
|
||||
|
||||
prepareLanesHandler := ChainPrepareLanes(registry)
|
||||
|
||||
// Fill the proposal with transactions from each lane.
|
||||
finalProposal, err := h.prepareLanesHandler(ctx, proposals.NewProposalWithContext(h.logger, ctx, h.txEncoder))
|
||||
finalProposal, err := 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
|
||||
@@ -133,14 +139,20 @@ func (h *ProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
|
||||
}()
|
||||
|
||||
// Extract all of the lanes and their corresponding transactions from the proposal.
|
||||
proposalInfo, partialProposals, err := h.ExtractLanes(req.Txs)
|
||||
proposalInfo, partialProposals, err := h.ExtractLanes(ctx, req.Txs)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to validate proposal", "err", err)
|
||||
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err
|
||||
}
|
||||
|
||||
// Build handler that will verify the partial proposals according to each lane's verification logic.
|
||||
processLanesHandler := ChainProcessLanes(partialProposals, h.mempool.Registry())
|
||||
registry, err := h.mempool.Registry(ctx)
|
||||
if err != nil {
|
||||
h.logger.Error("failed to get lane registry", "err", err)
|
||||
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, err
|
||||
}
|
||||
|
||||
processLanesHandler := ChainProcessLanes(partialProposals, registry)
|
||||
finalProposal, err := processLanesHandler(ctx, proposals.NewProposalWithContext(h.logger, ctx, h.txEncoder))
|
||||
if err != nil {
|
||||
h.logger.Error("failed to validate the proposal", "err", err)
|
||||
|
||||
+164
-15
@@ -15,10 +15,40 @@ import (
|
||||
|
||||
"github.com/skip-mev/block-sdk/abci"
|
||||
"github.com/skip-mev/block-sdk/block"
|
||||
"github.com/skip-mev/block-sdk/block/mocks"
|
||||
"github.com/skip-mev/block-sdk/block/proposals"
|
||||
testutils "github.com/skip-mev/block-sdk/testutils"
|
||||
blocksdkmoduletypes "github.com/skip-mev/block-sdk/x/blocksdk/types"
|
||||
)
|
||||
|
||||
type MockLaneFetcher struct {
|
||||
getLaneHandler func() (blocksdkmoduletypes.Lane, error)
|
||||
getLanesHandler func() []blocksdkmoduletypes.Lane
|
||||
}
|
||||
|
||||
func NewMockLaneFetcher(getLane func() (blocksdkmoduletypes.Lane, error), getLanes func() []blocksdkmoduletypes.Lane) MockLaneFetcher {
|
||||
return MockLaneFetcher{
|
||||
getLaneHandler: getLane,
|
||||
getLanesHandler: getLanes,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MockLaneFetcher) SetGetLaneHandler(h func() (blocksdkmoduletypes.Lane, error)) {
|
||||
m.getLaneHandler = h
|
||||
}
|
||||
|
||||
func (m MockLaneFetcher) GetLane(_ sdk.Context, _ string) (blocksdkmoduletypes.Lane, error) {
|
||||
return m.getLaneHandler()
|
||||
}
|
||||
|
||||
func (m *MockLaneFetcher) SetGetLanesHandler(h func() []blocksdkmoduletypes.Lane) {
|
||||
m.getLanesHandler = h
|
||||
}
|
||||
|
||||
func (m MockLaneFetcher) GetLanes(_ sdk.Context) []blocksdkmoduletypes.Lane {
|
||||
return m.getLanesHandler()
|
||||
}
|
||||
|
||||
type ProposalsTestSuite struct {
|
||||
suite.Suite
|
||||
ctx sdk.Context
|
||||
@@ -660,7 +690,34 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
|
||||
})
|
||||
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
|
||||
|
||||
mempool := block.NewLanedMempool(log.NewTestLogger(s.T()), false, panicLane, defaultLane)
|
||||
lanes := []block.Lane{
|
||||
panicLane,
|
||||
defaultLane,
|
||||
}
|
||||
|
||||
chainLanes := []blocksdkmoduletypes.Lane{
|
||||
{
|
||||
Id: panicLane.Name(),
|
||||
MaxBlockSpace: panicLane.GetMaxBlockSpace(),
|
||||
Order: 0,
|
||||
},
|
||||
{
|
||||
Id: defaultLane.Name(),
|
||||
MaxBlockSpace: defaultLane.GetMaxBlockSpace(),
|
||||
Order: 1,
|
||||
},
|
||||
}
|
||||
|
||||
mempool := block.NewLanedMempool(
|
||||
log.NewTestLogger(s.T()),
|
||||
false,
|
||||
mocks.NewMockLaneFetcher(func() (blocksdkmoduletypes.Lane, error) {
|
||||
return blocksdkmoduletypes.Lane{}, nil
|
||||
}, func() []blocksdkmoduletypes.Lane {
|
||||
return chainLanes
|
||||
}),
|
||||
lanes...,
|
||||
)
|
||||
|
||||
proposalHandler := abci.NewProposalHandler(
|
||||
log.NewTestLogger(s.T()),
|
||||
@@ -709,7 +766,34 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
|
||||
})
|
||||
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
|
||||
|
||||
mempool := block.NewLanedMempool(log.NewTestLogger(s.T()), false, defaultLane, panicLane)
|
||||
lanes := []block.Lane{
|
||||
defaultLane,
|
||||
panicLane,
|
||||
}
|
||||
|
||||
chainLanes := []blocksdkmoduletypes.Lane{
|
||||
{
|
||||
Id: panicLane.Name(),
|
||||
MaxBlockSpace: panicLane.GetMaxBlockSpace(),
|
||||
Order: 1,
|
||||
},
|
||||
{
|
||||
Id: defaultLane.Name(),
|
||||
MaxBlockSpace: defaultLane.GetMaxBlockSpace(),
|
||||
Order: 0,
|
||||
},
|
||||
}
|
||||
|
||||
mempool := block.NewLanedMempool(
|
||||
log.NewTestLogger(s.T()),
|
||||
false,
|
||||
mocks.NewMockLaneFetcher(func() (blocksdkmoduletypes.Lane, error) {
|
||||
return blocksdkmoduletypes.Lane{}, nil
|
||||
}, func() []blocksdkmoduletypes.Lane {
|
||||
return chainLanes
|
||||
}),
|
||||
lanes...,
|
||||
)
|
||||
|
||||
proposalHandler := abci.NewProposalHandler(
|
||||
log.NewTestLogger(s.T()),
|
||||
@@ -759,8 +843,40 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
|
||||
})
|
||||
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
|
||||
|
||||
mempool := block.NewLanedMempool(log.NewTestLogger(s.T()), false, panicLane, panicLane2, defaultLane)
|
||||
lanes := []block.Lane{
|
||||
panicLane,
|
||||
panicLane2,
|
||||
defaultLane,
|
||||
}
|
||||
|
||||
chainLanes := []blocksdkmoduletypes.Lane{
|
||||
{
|
||||
Id: panicLane.Name(),
|
||||
MaxBlockSpace: panicLane.GetMaxBlockSpace(),
|
||||
Order: 0,
|
||||
},
|
||||
{
|
||||
Id: panicLane2.Name(),
|
||||
MaxBlockSpace: panicLane2.GetMaxBlockSpace(),
|
||||
Order: 1,
|
||||
},
|
||||
{
|
||||
Id: defaultLane.Name(),
|
||||
MaxBlockSpace: defaultLane.GetMaxBlockSpace(),
|
||||
Order: 2,
|
||||
},
|
||||
}
|
||||
|
||||
mempool := block.NewLanedMempool(
|
||||
log.NewTestLogger(s.T()),
|
||||
false,
|
||||
mocks.NewMockLaneFetcher(func() (blocksdkmoduletypes.Lane, error) {
|
||||
return blocksdkmoduletypes.Lane{}, nil
|
||||
}, func() []blocksdkmoduletypes.Lane {
|
||||
return chainLanes
|
||||
}),
|
||||
lanes...,
|
||||
)
|
||||
proposalHandler := abci.NewProposalHandler(
|
||||
log.NewTestLogger(s.T()),
|
||||
s.encodingConfig.TxConfig.TxDecoder(),
|
||||
@@ -809,7 +925,40 @@ func (s *ProposalsTestSuite) TestPrepareProposalEdgeCases() {
|
||||
})
|
||||
s.Require().NoError(defaultLane.Insert(sdk.Context{}, tx))
|
||||
|
||||
mempool := block.NewLanedMempool(log.NewTestLogger(s.T()), false, defaultLane, panicLane, panicLane2)
|
||||
lanes := []block.Lane{
|
||||
defaultLane,
|
||||
panicLane,
|
||||
panicLane2,
|
||||
}
|
||||
|
||||
chainLanes := []blocksdkmoduletypes.Lane{
|
||||
{
|
||||
Id: panicLane.Name(),
|
||||
MaxBlockSpace: panicLane.GetMaxBlockSpace(),
|
||||
Order: 1,
|
||||
},
|
||||
{
|
||||
Id: panicLane2.Name(),
|
||||
MaxBlockSpace: panicLane2.GetMaxBlockSpace(),
|
||||
Order: 2,
|
||||
},
|
||||
{
|
||||
Id: defaultLane.Name(),
|
||||
MaxBlockSpace: defaultLane.GetMaxBlockSpace(),
|
||||
Order: 0,
|
||||
},
|
||||
}
|
||||
|
||||
mempool := block.NewLanedMempool(
|
||||
log.NewTestLogger(s.T()),
|
||||
false,
|
||||
mocks.NewMockLaneFetcher(func() (blocksdkmoduletypes.Lane, error) {
|
||||
return blocksdkmoduletypes.Lane{}, nil
|
||||
}, func() []blocksdkmoduletypes.Lane {
|
||||
return chainLanes
|
||||
}),
|
||||
lanes...,
|
||||
)
|
||||
|
||||
proposalHandler := abci.NewProposalHandler(
|
||||
log.NewTestLogger(s.T()),
|
||||
@@ -1454,7 +1603,7 @@ func (s *ProposalsTestSuite) TestIterateMempoolAndProcessProposalParity() {
|
||||
accounts := testutils.RandomAccounts(s.random, numAccounts)
|
||||
|
||||
// Create a bunch of transactions to insert into the default lane
|
||||
txsToInsert := []sdk.Tx{}
|
||||
var txsToInsert []sdk.Tx
|
||||
validationMap := make(map[sdk.Tx]bool)
|
||||
for _, account := range accounts {
|
||||
for nonce := uint64(0); nonce < numTxsPerAccount; nonce++ {
|
||||
@@ -1511,14 +1660,14 @@ func (s *ProposalsTestSuite) TestIterateMempoolAndProcessProposalParity() {
|
||||
}
|
||||
|
||||
// Retrieve the transactions from the default lane in the same way the prepare function would.
|
||||
retrievedTxs := []sdk.Tx{}
|
||||
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.
|
||||
freeRetrievedTxs := []sdk.Tx{}
|
||||
var freeRetrievedTxs []sdk.Tx
|
||||
for iterator := freelane.Select(context.Background(), nil); iterator != nil; iterator = iterator.Next() {
|
||||
freeRetrievedTxs = append(freeRetrievedTxs, iterator.Tx())
|
||||
}
|
||||
@@ -1557,7 +1706,7 @@ func (s *ProposalsTestSuite) TestValidateBasic() {
|
||||
info := s.createProposalInfoBytes(0, 0, 0, 0, nil)
|
||||
proposal := [][]byte{info}
|
||||
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(3, len(partialProposals))
|
||||
|
||||
@@ -1570,21 +1719,21 @@ func (s *ProposalsTestSuite) TestValidateBasic() {
|
||||
info := s.createProposalInfoBytes(0, 0, 0, 0, nil)
|
||||
proposal := [][]byte{info, {0x01, 0x02, 0x03}}
|
||||
|
||||
_, _, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, _, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().Error(err)
|
||||
})
|
||||
|
||||
s.Run("should invalidate proposal without info", func() {
|
||||
proposal := [][]byte{{0x01, 0x02, 0x03}}
|
||||
|
||||
_, _, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, _, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().Error(err)
|
||||
})
|
||||
|
||||
s.Run("should invalidate completely empty proposal", func() {
|
||||
proposal := [][]byte{}
|
||||
|
||||
_, _, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, _, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().Error(err)
|
||||
})
|
||||
|
||||
@@ -1592,7 +1741,7 @@ func (s *ProposalsTestSuite) TestValidateBasic() {
|
||||
info := s.createProposalInfoBytes(0, 0, 0, 0, nil)
|
||||
proposal := [][]byte{info, {0x01, 0x02, 0x03}, {0x01, 0x02, 0x03}}
|
||||
|
||||
_, _, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, _, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().Error(err)
|
||||
})
|
||||
|
||||
@@ -1622,7 +1771,7 @@ func (s *ProposalsTestSuite) TestValidateBasic() {
|
||||
|
||||
proposal = append([][]byte{info}, proposal...)
|
||||
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(3, len(partialProposals))
|
||||
@@ -1669,7 +1818,7 @@ func (s *ProposalsTestSuite) TestValidateBasic() {
|
||||
|
||||
proposal = append([][]byte{info}, proposal...)
|
||||
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(3, len(partialProposals))
|
||||
@@ -1730,7 +1879,7 @@ func (s *ProposalsTestSuite) TestValidateBasic() {
|
||||
|
||||
proposal = append([][]byte{info}, proposal...)
|
||||
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(proposal)
|
||||
_, partialProposals, err := proposalHandlers.ExtractLanes(s.ctx, proposal)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(3, len(partialProposals))
|
||||
|
||||
+5
-2
@@ -15,7 +15,7 @@ import (
|
||||
// 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) {
|
||||
func (h *ProposalHandler) ExtractLanes(ctx sdk.Context, 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")
|
||||
@@ -29,7 +29,10 @@ func (h *ProposalHandler) ExtractLanes(proposal [][]byte) (types.ProposalInfo, [
|
||||
return types.ProposalInfo{}, nil, fmt.Errorf("failed to unmarshal proposal metadata: %w", err)
|
||||
}
|
||||
|
||||
lanes := h.mempool.Registry()
|
||||
lanes, err := h.mempool.Registry(ctx)
|
||||
if err != nil {
|
||||
return types.ProposalInfo{}, nil, fmt.Errorf("failed to get mempool registry: %w", err)
|
||||
}
|
||||
partialProposals := make([][][]byte, len(lanes))
|
||||
|
||||
if metaData.TxsByLane == nil {
|
||||
|
||||
+26
-1
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
blocksdkmoduletypes "github.com/skip-mev/block-sdk/x/blocksdk/types"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/math"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@@ -63,6 +65,7 @@ func (s *ProposalsTestSuite) setUpStandardLane(maxBlockSpace math.LegacyDec, exp
|
||||
TxDecoder: s.encodingConfig.TxConfig.TxDecoder(),
|
||||
AnteHandler: s.setUpAnteHandler(expectedExecution),
|
||||
MaxBlockSpace: maxBlockSpace,
|
||||
IgnoreList: make([]block.Lane, 0),
|
||||
SignerExtractor: signeradaptors.NewDefaultAdapter(),
|
||||
}
|
||||
|
||||
@@ -118,7 +121,29 @@ func (s *ProposalsTestSuite) setUpPanicLane(maxBlockSpace math.LegacyDec) *base.
|
||||
}
|
||||
|
||||
func (s *ProposalsTestSuite) setUpProposalHandlers(lanes []block.Lane) *abci.ProposalHandler {
|
||||
mempool := block.NewLanedMempool(log.NewTestLogger(s.T()), true, lanes...)
|
||||
blocksdkLanes := make([]blocksdkmoduletypes.Lane, len(lanes))
|
||||
for i, lane := range lanes {
|
||||
blocksdkLanes[i] = blocksdkmoduletypes.Lane{
|
||||
Id: lane.Name(),
|
||||
MaxBlockSpace: lane.GetMaxBlockSpace(),
|
||||
Order: uint64(i),
|
||||
}
|
||||
}
|
||||
|
||||
laneFetcher := NewMockLaneFetcher(
|
||||
func() (blocksdkmoduletypes.Lane, error) {
|
||||
return blocksdkmoduletypes.Lane{}, nil
|
||||
},
|
||||
func() []blocksdkmoduletypes.Lane {
|
||||
return blocksdkLanes
|
||||
})
|
||||
|
||||
mempool := block.NewLanedMempool(log.NewTestLogger(
|
||||
s.T()),
|
||||
false,
|
||||
laneFetcher,
|
||||
lanes...,
|
||||
)
|
||||
|
||||
return abci.NewProposalHandler(
|
||||
log.NewTestLogger(s.T()),
|
||||
|
||||
Reference in New Issue
Block a user