feat: gRPC mempool service (#275)

* make file nit

* base app set up

* make file update

* makefile nit

* adding service test to e2e

* lint

* type fix

* nit

* unit test + readme
This commit is contained in:
David Terpay 2023-12-08 13:33:58 -05:00 committed by GitHub
parent 56eeeb3ea2
commit 7d8a6956a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1280 additions and 39 deletions

1
.gitignore vendored
View File

@ -13,6 +13,7 @@ profile.out
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
build/
tests/.testappd
# Dependency directories (remove the comment below to include it)
# vendor/

View File

@ -9,6 +9,9 @@ BUILD_DIR ?= $(CURDIR)/build
PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
HTTPS_GIT := https://github.com/skip-mev/block-sdk.git
DOCKER := $(shell which docker)
HOMEDIR ?= $(CURDIR)/tests/.testappd
GENESIS ?= $(HOMEDIR)/config/genesis.json
GENESIS_TMP ?= $(HOMEDIR)/config/genesis_tmp.json
COVER_FILE ?= "cover.out"
###############################################################################
@ -76,13 +79,15 @@ $(BUILD_DIR)/:
# other addresses using "genesis add-genesis-account address 10000000000000000000000000stake".
# This will allow users to bootstrap their wallet with a balance.
build-and-start-app: build-test-app
./build/testappd init validator1 --chain-id chain-id-0
./build/testappd keys add validator1
./build/testappd genesis add-genesis-account validator1 10000000000000000000000000stake
./build/testappd genesis add-genesis-account cosmos1see0htr47uapjvcvh0hu6385rp8lw3em24hysg 10000000000000000000000000stake
./build/testappd genesis gentx validator1 1000000000stake --chain-id chain-id-0
./build/testappd genesis collect-gentxs
./build/testappd start --api.enable true --api.enabled-unsafe-cors true --log_level info
rm -rf $(HOMEDIR)
./build/testappd init validator1 --chain-id chain-id-0 --home $(HOMEDIR)
./build/testappd keys add validator1 --home $(HOMEDIR) --keyring-backend test
./build/testappd genesis add-genesis-account validator1 10000000000000000000000000stake --home $(HOMEDIR) --keyring-backend test
./build/testappd genesis add-genesis-account cosmos1see0htr47uapjvcvh0hu6385rp8lw3em24hysg 10000000000000000000000000stake --home $(HOMEDIR) --keyring-backend test
./build/testappd genesis gentx validator1 1000000000stake --chain-id chain-id-0 --home $(HOMEDIR) --keyring-backend test
./build/testappd genesis collect-gentxs --home $(HOMEDIR)
./build/testappd start --api.enable false --api.enabled-unsafe-cors false --log_level info --home $(HOMEDIR)
.PHONY: build-test-app build-and-start-app

View File

@ -32,7 +32,7 @@ type (
Contains(tx sdk.Tx) bool
// GetTxDistribution returns the number of transactions in each lane.
GetTxDistribution() map[string]int
GetTxDistribution() map[string]uint64
}
// LanedMempool defines the Block SDK mempool implementation. It contains a registry
@ -86,11 +86,11 @@ func (m *LanedMempool) CountTx() int {
}
// GetTxDistribution returns the number of transactions in each lane.
func (m *LanedMempool) GetTxDistribution() map[string]int {
counts := make(map[string]int, len(m.registry))
func (m *LanedMempool) GetTxDistribution() map[string]uint64 {
counts := make(map[string]uint64, len(m.registry))
for _, lane := range m.registry {
counts[lane.Name()] = lane.CountTx()
counts[lane.Name()] = uint64(lane.CountTx())
}
return counts

View File

@ -288,43 +288,43 @@ func (suite *BlockBusterTestSuite) TestNewMempool() {
func (suite *BlockBusterTestSuite) TestInsert() {
cases := []struct {
name string
insertDistribution map[string]int
insertDistribution map[string]uint64
}{
{
"insert 1 mev tx",
map[string]int{
map[string]uint64{
suite.mevLane.Name(): 1,
},
},
{
"insert 10 mev txs",
map[string]int{
map[string]uint64{
suite.mevLane.Name(): 10,
},
},
{
"insert 1 base tx",
map[string]int{
map[string]uint64{
suite.baseLane.Name(): 1,
},
},
{
"insert 10 base txs and 10 mev txs",
map[string]int{
map[string]uint64{
suite.baseLane.Name(): 10,
suite.mevLane.Name(): 10,
},
},
{
"insert 100 base txs and 100 mev txs",
map[string]int{
map[string]uint64{
suite.baseLane.Name(): 100,
suite.mevLane.Name(): 100,
},
},
{
"insert 100 base txs, 100 mev txs, and 100 free txs",
map[string]int{
map[string]uint64{
suite.baseLane.Name(): 100,
suite.mevLane.Name(): 100,
suite.freeLane.Name(): 100,
@ -332,20 +332,20 @@ func (suite *BlockBusterTestSuite) TestInsert() {
},
{
"insert 10 free txs",
map[string]int{
map[string]uint64{
suite.freeLane.Name(): 10,
},
},
{
"insert 10 free txs and 10 base txs",
map[string]int{
map[string]uint64{
suite.freeLane.Name(): 10,
suite.baseLane.Name(): 10,
},
},
{
"insert 10 mev txs and 10 free txs",
map[string]int{
map[string]uint64{
suite.mevLane.Name(): 10,
suite.freeLane.Name(): 10,
},
@ -365,18 +365,18 @@ func (suite *BlockBusterTestSuite) TestInsert() {
// Fill the Free lane with numFreeTxs transactions
suite.fillFreeLane(tc.insertDistribution[suite.freeLane.Name()])
sum := 0
sum := uint64(0)
for _, v := range tc.insertDistribution {
sum += v
}
// Validate the mempool
suite.Require().Equal(sum, suite.mempool.CountTx())
suite.Require().Equal(int(sum), suite.mempool.CountTx())
// Validate the lanes
suite.Require().Equal(tc.insertDistribution[suite.mevLane.Name()], suite.mevLane.CountTx())
suite.Require().Equal(tc.insertDistribution[suite.baseLane.Name()], suite.baseLane.CountTx())
suite.Require().Equal(tc.insertDistribution[suite.freeLane.Name()], suite.freeLane.CountTx())
suite.Require().Equal(tc.insertDistribution[suite.mevLane.Name()], uint64(suite.mevLane.CountTx()))
suite.Require().Equal(tc.insertDistribution[suite.baseLane.Name()], uint64(suite.baseLane.CountTx()))
suite.Require().Equal(tc.insertDistribution[suite.freeLane.Name()], uint64(suite.freeLane.CountTx()))
// Validate the lane counts
laneCounts := suite.mempool.GetTxDistribution()
@ -392,8 +392,8 @@ func (suite *BlockBusterTestSuite) TestInsert() {
func (suite *BlockBusterTestSuite) TestRemove() {
cases := []struct {
name string
numTobTxs int
numBaseTxs int
numTobTxs uint64
numBaseTxs uint64
}{
{
"insert 1 mev tx",
@ -446,7 +446,7 @@ func (suite *BlockBusterTestSuite) TestRemove() {
// Ensure the number of transactions in the lane is correct
baseCount--
suite.Require().Equal(suite.baseLane.CountTx(), baseCount)
suite.Require().Equal(suite.baseLane.CountTx(), int(baseCount))
distribution := suite.mempool.GetTxDistribution()
suite.Require().Equal(distribution[suite.baseLane.Name()], baseCount)
@ -455,7 +455,7 @@ func (suite *BlockBusterTestSuite) TestRemove() {
}
suite.Require().Equal(0, suite.baseLane.CountTx())
suite.Require().Equal(mevCount, suite.mevLane.CountTx())
suite.Require().Equal(int(mevCount), suite.mevLane.CountTx())
// Remove all transactions from the lanes
for iterator := suite.mevLane.Select(suite.ctx, nil); iterator != nil; {
@ -469,7 +469,7 @@ func (suite *BlockBusterTestSuite) TestRemove() {
// Ensure the number of transactions in the lane is correct
mevCount--
suite.Require().Equal(suite.mevLane.CountTx(), mevCount)
suite.Require().Equal(suite.mevLane.CountTx(), int(mevCount))
distribution := suite.mempool.GetTxDistribution()
suite.Require().Equal(distribution[suite.mevLane.Name()], mevCount)
@ -485,15 +485,15 @@ func (suite *BlockBusterTestSuite) TestRemove() {
distribution := suite.mempool.GetTxDistribution()
// Ensure that the lane counts are correct
suite.Require().Equal(distribution[suite.mevLane.Name()], 0)
suite.Require().Equal(distribution[suite.baseLane.Name()], 0)
suite.Require().Equal(distribution[suite.mevLane.Name()], uint64(0))
suite.Require().Equal(distribution[suite.baseLane.Name()], uint64(0))
})
}
}
// fillBaseLane fills the base lane with numTxs transactions that are randomly created.
func (suite *BlockBusterTestSuite) fillBaseLane(numTxs int) {
for i := 0; i < numTxs; i++ {
func (suite *BlockBusterTestSuite) fillBaseLane(numTxs uint64) {
for i := uint64(0); i < numTxs; i++ {
// randomly select an account to create the tx
randomIndex := suite.random.Intn(len(suite.accounts))
acc := suite.accounts[randomIndex]
@ -512,8 +512,8 @@ func (suite *BlockBusterTestSuite) fillBaseLane(numTxs int) {
}
// fillTOBLane fills the TOB lane with numTxs transactions that are randomly created.
func (suite *BlockBusterTestSuite) fillTOBLane(numTxs int) {
for i := 0; i < numTxs; i++ {
func (suite *BlockBusterTestSuite) fillTOBLane(numTxs uint64) {
for i := uint64(0); i < numTxs; i++ {
// randomly select a bidder to create the tx
randomIndex := suite.random.Intn(len(suite.accounts))
acc := suite.accounts[randomIndex]
@ -532,8 +532,8 @@ func (suite *BlockBusterTestSuite) fillTOBLane(numTxs int) {
}
// filleFreeLane fills the free lane with numTxs transactions that are randomly created.
func (suite *BlockBusterTestSuite) fillFreeLane(numTxs int) {
for i := 0; i < numTxs; i++ {
func (suite *BlockBusterTestSuite) fillFreeLane(numTxs uint64) {
for i := uint64(0); i < numTxs; i++ {
// randomly select an account to create the tx
randomIndex := suite.random.Intn(len(suite.accounts))
acc := suite.accounts[randomIndex]

56
block/service/README.md Normal file
View File

@ -0,0 +1,56 @@
# Block SDK Mempool Service
The Block SDK mempool service is a service that allows you to query the current state of the application side mempool.
## Usage
The mempool service is a standard gRPC service that can be paired with http or grpc clients.
### HTTP Clients
To make requests to the mempool service using HTTP, you have to use the grpc-gateway defined on your application's server. This is usually hosted on port 1317.
### gRPC Clients
To query the mempool service using gRPC, you can use the Mempool `ServiceClient` defined in [types](./types/query.pb.go):
```golang
type serviceClient struct {
cc grpc1.ClientConn
}
func NewServiceClient(cc grpc1.ClientConn) ServiceClient {
return &serviceClient{cc}
}
func (c *serviceClient) GetTxDistribution(ctx context.Context, in *GetTxDistributionRequest, opts ...grpc.CallOption) (*GetTxDistributionResponse, error) {
out := new(GetTxDistributionResponse)
err := c.cc.Invoke(ctx, "/sdk.mempool.v1.Service/GetTxDistribution", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
```
## Endpoints
### GetTxDistribution
GetTxDistribution returns the current distribution of transactions in the mempool. The response is a map of the lane name to the number of transactions in that lane.
```golang
type GetTxDistributionRequest struct {}
type GetTxDistributionResponse struct {
Distribution map[string]uint64
}
```
### HTTP Requests
To query the mempool service using HTTP, you can use the following endpoint:
```bash
curl http://localhost:1317/block-sdk/mempool/v1/distribution
```

54
block/service/service.go Normal file
View File

@ -0,0 +1,54 @@
package service
import (
"context"
gogogrpc "github.com/cosmos/gogoproto/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/service/types"
)
var _ types.ServiceServer = (*QueryService)(nil)
// QueryService defines the service used by the gRPC query server to query the
// Block SDK mempool.
type QueryService struct {
types.UnimplementedServiceServer
// mempool is the mempool instance to query.
mempool block.Mempool
}
// NewQueryService creates a new QueryService instance.
func NewQueryService(mempool block.Mempool) *QueryService {
return &QueryService{
mempool: mempool,
}
}
// GetTxDistribution returns the current distribution of transactions in the
// mempool.
func (s *QueryService) GetTxDistribution(
_ context.Context,
_ *types.GetTxDistributionRequest,
) (*types.GetTxDistributionResponse, error) {
distribution := s.mempool.GetTxDistribution()
return &types.GetTxDistributionResponse{Distribution: distribution}, nil
}
// RegisterMempoolService registers the Block SDK mempool queries on the gRPC server.
func RegisterMempoolService(
server gogogrpc.Server,
mempool block.Mempool,
) {
types.RegisterServiceServer(server, NewQueryService(mempool))
}
// RegisterGRPCGatewayRoutes mounts the Block SDK mempool service's GRPC-gateway routes on the
// given Mux.
func RegisterGRPCGatewayRoutes(clientConn gogogrpc.ClientConn, mux *runtime.ServeMux) {
_ = types.RegisterServiceHandlerClient(context.Background(), mux, types.NewServiceClient(clientConn))
}

View File

@ -0,0 +1,192 @@
package service_test
import (
"context"
"math/rand"
"testing"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/service"
"github.com/skip-mev/block-sdk/block/service/types"
"github.com/skip-mev/block-sdk/lanes/base"
"github.com/skip-mev/block-sdk/lanes/free"
"github.com/skip-mev/block-sdk/lanes/mev"
"github.com/skip-mev/block-sdk/testutils"
"github.com/stretchr/testify/require"
)
func TestGetTxDistribution(t *testing.T) {
config := testutils.CreateTestEncodingConfig()
accounts := testutils.RandomAccounts(rand.New(rand.NewSource(1)), 3)
ctx := testutils.CreateBaseSDKContext(t)
testCases := []struct {
name string
mempool func() *block.LanedMempool
expectedDistribution map[string]uint64
}{
{
name: "returns correct distribution with no transactions",
mempool: testutils.CreateMempool,
expectedDistribution: map[string]uint64{
mev.LaneName: 0,
free.LaneName: 0,
base.LaneName: 0,
},
},
{
name: "only default lane has transactions",
mempool: func() *block.LanedMempool {
tx1, err := testutils.CreateRandomTx(
config.TxConfig,
accounts[0],
0,
1,
0,
0,
sdk.NewCoin("skip", math.NewInt(1)),
)
require.NoError(t, err)
tx2, err := testutils.CreateRandomTx(
config.TxConfig,
accounts[1],
0,
1,
0,
0,
sdk.NewCoin("skip", math.NewInt(1)),
)
require.NoError(t, err)
mempool := testutils.CreateMempool()
err = mempool.Insert(ctx, tx1)
require.NoError(t, err)
err = mempool.Insert(ctx, tx2)
require.NoError(t, err)
return mempool
},
expectedDistribution: map[string]uint64{
mev.LaneName: 0,
free.LaneName: 0,
base.LaneName: 2,
},
},
{
name: "only free lane has transactions",
mempool: func() *block.LanedMempool {
tx1, err := testutils.CreateFreeTx(
config.TxConfig,
accounts[0],
0,
1,
"skip",
sdk.NewCoin("skip", math.NewInt(1)),
)
require.NoError(t, err)
mempool := testutils.CreateMempool()
err = mempool.Insert(ctx, tx1)
require.NoError(t, err)
return mempool
},
expectedDistribution: map[string]uint64{
mev.LaneName: 0,
free.LaneName: 1,
base.LaneName: 0,
},
},
{
name: "only mev lane has transactions",
mempool: func() *block.LanedMempool {
tx1, err := testutils.CreateAuctionTxWithSigners(
config.TxConfig,
accounts[0],
sdk.NewCoin("skip", math.NewInt(1)),
0,
0,
accounts,
)
require.NoError(t, err)
mempool := testutils.CreateMempool()
err = mempool.Insert(ctx, tx1)
require.NoError(t, err)
return mempool
},
expectedDistribution: map[string]uint64{
mev.LaneName: 1,
free.LaneName: 0,
base.LaneName: 0,
},
},
{
name: "all lanes have transactions",
mempool: func() *block.LanedMempool {
mevTx, err := testutils.CreateAuctionTxWithSigners(
config.TxConfig,
accounts[0],
sdk.NewCoin("skip", math.NewInt(1)),
0,
0,
accounts,
)
require.NoError(t, err)
freeTx, err := testutils.CreateFreeTx(
config.TxConfig,
accounts[0],
0,
1,
"skip",
sdk.NewCoin("skip", math.NewInt(1)),
)
require.NoError(t, err)
baseTx, err := testutils.CreateRandomTx(
config.TxConfig,
accounts[0],
0,
1,
0,
0,
sdk.NewCoin("skip", math.NewInt(1)),
)
require.NoError(t, err)
mempool := testutils.CreateMempool()
err = mempool.Insert(ctx, mevTx)
require.NoError(t, err)
err = mempool.Insert(ctx, freeTx)
require.NoError(t, err)
err = mempool.Insert(ctx, baseTx)
require.NoError(t, err)
return mempool
},
expectedDistribution: map[string]uint64{
mev.LaneName: 1,
free.LaneName: 1,
base.LaneName: 1,
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mempool := tc.mempool()
queryService := service.NewQueryService(mempool)
ctx := context.Background()
distributionResponse, err := queryService.GetTxDistribution(ctx, &types.GetTxDistributionRequest{})
require.NoError(t, err)
require.Equal(t, tc.expectedDistribution, distributionResponse.Distribution)
})
}
}

View File

@ -0,0 +1,633 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: sdk/mempool/v1/query.proto
package types
import (
context "context"
fmt "fmt"
grpc1 "github.com/cosmos/gogoproto/grpc"
proto "github.com/cosmos/gogoproto/proto"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GetTxDistributionRequest is the request type for the Service.GetTxDistribution
// RPC method.
type GetTxDistributionRequest struct {
}
func (m *GetTxDistributionRequest) Reset() { *m = GetTxDistributionRequest{} }
func (m *GetTxDistributionRequest) String() string { return proto.CompactTextString(m) }
func (*GetTxDistributionRequest) ProtoMessage() {}
func (*GetTxDistributionRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_2b59d6882c9c3543, []int{0}
}
func (m *GetTxDistributionRequest) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GetTxDistributionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GetTxDistributionRequest.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GetTxDistributionRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetTxDistributionRequest.Merge(m, src)
}
func (m *GetTxDistributionRequest) XXX_Size() int {
return m.Size()
}
func (m *GetTxDistributionRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetTxDistributionRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetTxDistributionRequest proto.InternalMessageInfo
// GetTxDistributionResponse is the response type for the Service.GetTxDistribution
// RPC method.
type GetTxDistributionResponse struct {
// Distribution is a map of lane to the number of transactions in the mempool for that lane.
Distribution map[string]uint64 `protobuf:"bytes,1,rep,name=distribution,proto3" json:"distribution,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
}
func (m *GetTxDistributionResponse) Reset() { *m = GetTxDistributionResponse{} }
func (m *GetTxDistributionResponse) String() string { return proto.CompactTextString(m) }
func (*GetTxDistributionResponse) ProtoMessage() {}
func (*GetTxDistributionResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_2b59d6882c9c3543, []int{1}
}
func (m *GetTxDistributionResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GetTxDistributionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GetTxDistributionResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GetTxDistributionResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetTxDistributionResponse.Merge(m, src)
}
func (m *GetTxDistributionResponse) XXX_Size() int {
return m.Size()
}
func (m *GetTxDistributionResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GetTxDistributionResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GetTxDistributionResponse proto.InternalMessageInfo
func (m *GetTxDistributionResponse) GetDistribution() map[string]uint64 {
if m != nil {
return m.Distribution
}
return nil
}
func init() {
proto.RegisterType((*GetTxDistributionRequest)(nil), "sdk.mempool.v1.GetTxDistributionRequest")
proto.RegisterType((*GetTxDistributionResponse)(nil), "sdk.mempool.v1.GetTxDistributionResponse")
proto.RegisterMapType((map[string]uint64)(nil), "sdk.mempool.v1.GetTxDistributionResponse.DistributionEntry")
}
func init() { proto.RegisterFile("sdk/mempool/v1/query.proto", fileDescriptor_2b59d6882c9c3543) }
var fileDescriptor_2b59d6882c9c3543 = []byte{
// 326 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2a, 0x4e, 0xc9, 0xd6,
0xcf, 0x4d, 0xcd, 0x2d, 0xc8, 0xcf, 0xcf, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa,
0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x2b, 0x4e, 0xc9, 0xd6, 0x83, 0xca, 0xe9, 0x95,
0x19, 0x4a, 0xc9, 0xa4, 0xe7, 0xe7, 0xa7, 0xe7, 0xa4, 0xea, 0x27, 0x16, 0x64, 0xea, 0x27, 0xe6,
0xe5, 0xe5, 0x97, 0x24, 0x96, 0x64, 0xe6, 0xe7, 0x15, 0x43, 0x54, 0x2b, 0x49, 0x71, 0x49, 0xb8,
0xa7, 0x96, 0x84, 0x54, 0xb8, 0x64, 0x16, 0x97, 0x14, 0x65, 0x26, 0x95, 0x82, 0xe4, 0x82, 0x52,
0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x94, 0xf6, 0x32, 0x72, 0x49, 0x62, 0x91, 0x2c, 0x2e, 0xc8, 0xcf,
0x2b, 0x4e, 0x15, 0x8a, 0xe7, 0xe2, 0x49, 0x41, 0x12, 0x97, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x36,
0xb2, 0xd6, 0x43, 0xb5, 0x5e, 0x0f, 0xa7, 0x01, 0x7a, 0xc8, 0x82, 0xae, 0x79, 0x25, 0x45, 0x95,
0x41, 0x28, 0x06, 0x4a, 0xd9, 0x73, 0x09, 0x62, 0x28, 0x11, 0x12, 0xe0, 0x62, 0xce, 0x4e, 0xad,
0x94, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0x02, 0x31, 0x85, 0x44, 0xb8, 0x58, 0xcb, 0x12, 0x73,
0x4a, 0x53, 0x25, 0x98, 0x14, 0x18, 0x35, 0x58, 0x82, 0x20, 0x1c, 0x2b, 0x26, 0x0b, 0x46, 0xa3,
0x05, 0x8c, 0x5c, 0xec, 0xc1, 0xa9, 0x45, 0x65, 0x99, 0xc9, 0xa9, 0x42, 0x53, 0x18, 0xb9, 0x04,
0x31, 0x9c, 0x22, 0xa4, 0x41, 0x84, 0x6b, 0xc1, 0x61, 0x21, 0xa5, 0x49, 0xb4, 0xbf, 0x94, 0xb4,
0x9a, 0x2e, 0x3f, 0x99, 0xcc, 0xa4, 0x22, 0xa4, 0xa4, 0x9f, 0x94, 0x93, 0x9f, 0x9c, 0xad, 0x8b,
0x16, 0x57, 0xc8, 0x7e, 0x74, 0xf2, 0x3e, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07,
0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86,
0x28, 0xc3, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xe2, 0xec, 0xcc,
0x02, 0xdd, 0xdc, 0xd4, 0x32, 0x24, 0x03, 0xc1, 0x2c, 0xfd, 0x62, 0x88, 0xef, 0xf4, 0x4b, 0x2a,
0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0x51, 0x6a, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xfb, 0xaf,
0x0d, 0xf5, 0x1e, 0x02, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// ServiceClient is the client API for Service service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ServiceClient interface {
// GetTxDistribution returns the distribution of transactions in the mempool.
GetTxDistribution(ctx context.Context, in *GetTxDistributionRequest, opts ...grpc.CallOption) (*GetTxDistributionResponse, error)
}
type serviceClient struct {
cc grpc1.ClientConn
}
func NewServiceClient(cc grpc1.ClientConn) ServiceClient {
return &serviceClient{cc}
}
func (c *serviceClient) GetTxDistribution(ctx context.Context, in *GetTxDistributionRequest, opts ...grpc.CallOption) (*GetTxDistributionResponse, error) {
out := new(GetTxDistributionResponse)
err := c.cc.Invoke(ctx, "/sdk.mempool.v1.Service/GetTxDistribution", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ServiceServer is the server API for Service service.
type ServiceServer interface {
// GetTxDistribution returns the distribution of transactions in the mempool.
GetTxDistribution(context.Context, *GetTxDistributionRequest) (*GetTxDistributionResponse, error)
}
// UnimplementedServiceServer can be embedded to have forward compatible implementations.
type UnimplementedServiceServer struct {
}
func (*UnimplementedServiceServer) GetTxDistribution(ctx context.Context, req *GetTxDistributionRequest) (*GetTxDistributionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetTxDistribution not implemented")
}
func RegisterServiceServer(s grpc1.Server, srv ServiceServer) {
s.RegisterService(&_Service_serviceDesc, srv)
}
func _Service_GetTxDistribution_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetTxDistributionRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).GetTxDistribution(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/sdk.mempool.v1.Service/GetTxDistribution",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).GetTxDistribution(ctx, req.(*GetTxDistributionRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Service_serviceDesc = grpc.ServiceDesc{
ServiceName: "sdk.mempool.v1.Service",
HandlerType: (*ServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetTxDistribution",
Handler: _Service_GetTxDistribution_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "sdk/mempool/v1/query.proto",
}
func (m *GetTxDistributionRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GetTxDistributionRequest) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GetTxDistributionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
return len(dAtA) - i, nil
}
func (m *GetTxDistributionResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GetTxDistributionResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GetTxDistributionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Distribution) > 0 {
for k := range m.Distribution {
v := m.Distribution[k]
baseI := i
i = encodeVarintQuery(dAtA, i, uint64(v))
i--
dAtA[i] = 0x10
i -= len(k)
copy(dAtA[i:], k)
i = encodeVarintQuery(dAtA, i, uint64(len(k)))
i--
dAtA[i] = 0xa
i = encodeVarintQuery(dAtA, i, uint64(baseI-i))
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func encodeVarintQuery(dAtA []byte, offset int, v uint64) int {
offset -= sovQuery(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *GetTxDistributionRequest) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
return n
}
func (m *GetTxDistributionResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Distribution) > 0 {
for k, v := range m.Distribution {
_ = k
_ = v
mapEntrySize := 1 + len(k) + sovQuery(uint64(len(k))) + 1 + sovQuery(uint64(v))
n += mapEntrySize + 1 + sovQuery(uint64(mapEntrySize))
}
}
return n
}
func sovQuery(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozQuery(x uint64) (n int) {
return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *GetTxDistributionRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GetTxDistributionRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GetTxDistributionRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
iNdEx = preIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GetTxDistributionResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GetTxDistributionResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GetTxDistributionResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Distribution", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthQuery
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthQuery
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Distribution == nil {
m.Distribution = make(map[string]uint64)
}
var mapkey string
var mapvalue uint64
for iNdEx < postIndex {
entryPreIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
if fieldNum == 1 {
var stringLenmapkey uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLenmapkey |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLenmapkey := int(stringLenmapkey)
if intStringLenmapkey < 0 {
return ErrInvalidLengthQuery
}
postStringIndexmapkey := iNdEx + intStringLenmapkey
if postStringIndexmapkey < 0 {
return ErrInvalidLengthQuery
}
if postStringIndexmapkey > l {
return io.ErrUnexpectedEOF
}
mapkey = string(dAtA[iNdEx:postStringIndexmapkey])
iNdEx = postStringIndexmapkey
} else if fieldNum == 2 {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowQuery
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
mapvalue |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
} else {
iNdEx = entryPreIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > postIndex {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
m.Distribution[mapkey] = mapvalue
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipQuery(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthQuery
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipQuery(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowQuery
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowQuery
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowQuery
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthQuery
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupQuery
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthQuery
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -0,0 +1,153 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: sdk/mempool/v1/query.proto
/*
Package types is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package types
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var _ = metadata.Join
func request_Service_GetTxDistribution_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetTxDistributionRequest
var metadata runtime.ServerMetadata
msg, err := client.GetTxDistribution(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Service_GetTxDistribution_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq GetTxDistributionRequest
var metadata runtime.ServerMetadata
msg, err := server.GetTxDistribution(ctx, &protoReq)
return msg, metadata, err
}
// RegisterServiceHandlerServer registers the http handlers for service Service to "mux".
// UnaryRPC :call ServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterServiceHandlerFromEndpoint instead.
func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ServiceServer) error {
mux.Handle("GET", pattern_Service_GetTxDistribution_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Service_GetTxDistribution_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_GetTxDistribution_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterServiceHandlerFromEndpoint is same as RegisterServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterServiceHandler(ctx, mux, conn)
}
// RegisterServiceHandler registers the http handlers for service Service to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterServiceHandlerClient(ctx, mux, NewServiceClient(conn))
}
// RegisterServiceHandlerClient registers the http handlers for service Service
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ServiceClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ServiceClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "ServiceClient" to call the correct interceptors.
func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ServiceClient) error {
mux.Handle("GET", pattern_Service_GetTxDistribution_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Service_GetTxDistribution_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_GetTxDistribution_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Service_GetTxDistribution_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"block-sdk", "mempool", "v1", "distribution"}, "", runtime.AssumeColonVerbOpt(false)))
)
var (
forward_Service_GetTxDistribution_0 = runtime.ForwardResponseMessage
)

View File

@ -0,0 +1,27 @@
syntax = "proto3";
package sdk.mempool.v1;
option go_package = "github.com/skip-mev/block-sdk/block/service/types";
import "google/api/annotations.proto";
// Service defines the gRPC querier service for the Block SDK mempool.
service Service {
// GetTxDistribution returns the distribution of transactions in the mempool.
rpc GetTxDistribution(GetTxDistributionRequest) returns (GetTxDistributionResponse) {
option (google.api.http) = {
get: "/block-sdk/mempool/v1/distribution"
};
}
}
// GetTxDistributionRequest is the request type for the Service.GetTxDistribution
// RPC method.
message GetTxDistributionRequest {}
// GetTxDistributionResponse is the response type for the Service.GetTxDistribution
// RPC method.
message GetTxDistributionResponse {
// Distribution is a map of lane to the number of transactions in the mempool for that lane.
map<string, uint64> distribution = 1;
}

View File

@ -44,6 +44,7 @@ import (
"github.com/skip-mev/block-sdk/abci"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
service "github.com/skip-mev/block-sdk/block/service"
"github.com/skip-mev/block-sdk/lanes/mev"
auctionkeeper "github.com/skip-mev/block-sdk/x/auction/keeper"
blocksdkkeeper "github.com/skip-mev/block-sdk/x/blocksdk/keeper"
@ -385,13 +386,31 @@ func (app *TestApp) SimulationManager() *module.SimulationManager {
// RegisterAPIRoutes registers all application module routes with the provided
// API server.
func (app *TestApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
// Register the base app API routes.
app.App.RegisterAPIRoutes(apiSvr, apiConfig)
// Register the Block SDK mempool API routes.
service.RegisterGRPCGatewayRoutes(apiSvr.ClientCtx, apiSvr.GRPCGatewayRouter)
// register swagger API in app.go so that other applications can override easily
if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
panic(err)
}
}
// RegisterTxService implements the Application.RegisterTxService method.
func (app *TestApp) RegisterTxService(clientCtx client.Context) {
// Register the base app transaction service.
app.App.RegisterTxService(clientCtx)
// Register the Block SDK mempool transaction service.
mempool, ok := app.App.Mempool().(block.Mempool)
if !ok {
panic("mempool is not a block.Mempool")
}
service.RegisterMempoolService(app.GRPCQueryRouter(), mempool)
}
// GetMaccPerms returns a copy of the module account permissions
//
// NOTE: This is solely to be used for testing purposes.

View File

@ -12,6 +12,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/skip-mev/block-sdk/lanes/base"
"github.com/skip-mev/block-sdk/lanes/free"
interchaintest "github.com/strangelove-ventures/interchaintest/v8"
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
@ -121,6 +123,12 @@ func (s *IntegrationTestSuite) TestQueryParams() {
require.NoError(s.T(), params.Validate())
}
func (s *IntegrationTestSuite) TestMempoolService() {
resp, err := QueryMempool(s.T(), s.chain)
s.Require().NoError(err)
s.Require().Len(resp.Distribution, 3)
}
// TestValidBids tests the execution of various valid auction bids. There are a few
// invariants that are tested:
//
@ -1298,6 +1306,10 @@ func (s *IntegrationTestSuite) TestNetwork() {
s.BroadcastTxs(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{normalTx})
}
}
resp, err := QueryMempool(s.T(), s.chain)
s.NoError(err)
s.Require().True(resp.Distribution[base.LaneName] > 0)
}
}
})
@ -1322,6 +1334,10 @@ func (s *IntegrationTestSuite) TestNetwork() {
s.BroadcastTxs(context.Background(), s.chain.(*cosmos.CosmosChain), []Tx{freeTx})
}
}
resp, err := QueryMempool(s.T(), s.chain)
s.NoError(err)
s.Require().True(resp.Distribution[free.LaneName] > 0)
}
}
})

View File

@ -37,6 +37,7 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
servicetypes "github.com/skip-mev/block-sdk/block/service/types"
auctiontypes "github.com/skip-mev/block-sdk/x/auction/types"
)
@ -367,6 +368,18 @@ func QueryValidators(t *testing.T, chain *cosmos.CosmosChain) []sdk.ValAddress {
return addrs
}
// QueryMempool queries the mempool of the given chain
func QueryMempool(t *testing.T, chain ibc.Chain) (*servicetypes.GetTxDistributionResponse, error) {
// get grpc client of the node
grpcAddr := chain.GetHostGRPCAddress()
cc, err := grpc.Dial(grpcAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
require.NoError(t, err)
client := servicetypes.NewServiceClient(cc)
return client.GetTxDistribution(context.Background(), &servicetypes.GetTxDistributionRequest{})
}
// QueryAccountBalance queries a given account's balance on the chain
func QueryAccountBalance(t *testing.T, chain ibc.Chain, address, denom string) int64 {
// cast the chain to a cosmos-chain

View File

@ -2,7 +2,11 @@ package testutils
import (
"math/rand"
"testing"
"cosmossdk.io/log"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
txsigning "cosmossdk.io/x/tx/signing"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
@ -12,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
@ -20,6 +25,13 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/gogoproto/proto"
signerextraction "github.com/skip-mev/block-sdk/adapters/signer_extraction_adapter"
"github.com/skip-mev/block-sdk/block"
"github.com/skip-mev/block-sdk/block/base"
"github.com/skip-mev/block-sdk/block/mocks"
defaultlane "github.com/skip-mev/block-sdk/lanes/base"
"github.com/skip-mev/block-sdk/lanes/free"
"github.com/skip-mev/block-sdk/lanes/mev"
auctiontypes "github.com/skip-mev/block-sdk/x/auction/types"
)
@ -30,6 +42,66 @@ type EncodingConfig struct {
Amino *codec.LegacyAmino
}
// CreateBaseSDKContext creates a base sdk context with the default store key and transient key.
func CreateBaseSDKContext(t *testing.T) sdk.Context {
key := storetypes.NewKVStoreKey(auctiontypes.StoreKey)
testCtx := testutil.DefaultContextWithDB(
t,
key,
storetypes.NewTransientStoreKey("transient_test"),
)
return testCtx.Ctx
}
func CreateMempool() *block.LanedMempool {
encodingConfig := CreateTestEncodingConfig()
signerExtractor := signerextraction.NewDefaultAdapter()
mevConfig := base.LaneConfig{
SignerExtractor: signerExtractor,
Logger: log.NewNopLogger(),
TxEncoder: encodingConfig.TxConfig.TxEncoder(),
TxDecoder: encodingConfig.TxConfig.TxDecoder(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
MaxTxs: 0, // unlimited
}
factory := mev.NewDefaultAuctionFactory(encodingConfig.TxConfig.TxDecoder(), signerExtractor)
mevLane := mev.NewMEVLane(mevConfig, factory, factory.MatchHandler())
freeConfig := base.LaneConfig{
SignerExtractor: signerExtractor,
Logger: log.NewNopLogger(),
TxEncoder: encodingConfig.TxConfig.TxEncoder(),
TxDecoder: encodingConfig.TxConfig.TxDecoder(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
MaxTxs: 0, // unlimited
}
freeLane := free.NewFreeLane[string](freeConfig, base.DefaultTxPriority(), free.DefaultMatchHandler())
defaultConfig := base.LaneConfig{
SignerExtractor: signerExtractor,
Logger: log.NewNopLogger(),
TxEncoder: encodingConfig.TxConfig.TxEncoder(),
TxDecoder: encodingConfig.TxConfig.TxDecoder(),
AnteHandler: nil,
MaxBlockSpace: math.LegacyZeroDec(),
MaxTxs: 0, // unlimited
}
defaultLane := defaultlane.NewDefaultLane(defaultConfig, base.DefaultMatchHandler())
lanes := []block.Lane{mevLane, freeLane, defaultLane}
mempool, err := block.NewLanedMempool(log.NewNopLogger(), lanes, mocks.MockLaneFetcher{})
if err != nil {
panic(err)
}
return mempool
}
func CreateTestEncodingConfig() EncodingConfig {
interfaceRegistry, err := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,