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:
Alex Johnson
2023-11-07 16:22:17 -05:00
committed by GitHub
co-authored by Keefer Taylor | Tessellated aljo242
parent f5457e3e54
commit 41e85e9cfe
16 changed files with 804 additions and 104 deletions
+25 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()),