From accde565083157717aec17a0118a205b4b1069e2 Mon Sep 17 00:00:00 2001 From: Sean McGary Date: Thu, 16 Jan 2025 15:24:19 -0600 Subject: [PATCH] feat: GetDelegatedStakersForOperator rpc --- go.mod | 2 +- go.sum | 6 ++ pkg/rpcServer/protocolHandlers.go | 32 +++++++++- pkg/service/protocolDataService/protocol.go | 70 ++++++++++++++++++--- pkg/service/types/pagination.go | 21 ++++++- 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 3cba7042..d1121c58 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/DataDog/datadog-go/v5 v5.5.0 github.com/Layr-Labs/eigenlayer-contracts v0.4.1-holesky-pepe.0.20240813143901-00fc4b95e9c1 github.com/Layr-Labs/eigenlayer-rewards-proofs v0.2.13 - github.com/Layr-Labs/protocol-apis v1.1.1-0.20250115230325-93c4ebccbeb7 + github.com/Layr-Labs/protocol-apis v1.1.1-0.20250121193118-8112817d1079 github.com/ethereum/go-ethereum v1.14.9 github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/google/uuid v1.6.0 diff --git a/go.sum b/go.sum index 3c546f54..3e9c0f1a 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,12 @@ github.com/Layr-Labs/protocol-apis v1.1.1-0.20250115220323-135176acb92b h1:eJmPA github.com/Layr-Labs/protocol-apis v1.1.1-0.20250115220323-135176acb92b/go.mod h1:prNA2/mLO5vpMZ2q78Nsn0m97wm28uiRnwO+/yOxigk= github.com/Layr-Labs/protocol-apis v1.1.1-0.20250115230325-93c4ebccbeb7 h1:zTOIFjJcCzOZ1PBk9jtoW/bsKSyRzvQyTG2Beutpiuk= github.com/Layr-Labs/protocol-apis v1.1.1-0.20250115230325-93c4ebccbeb7/go.mod h1:prNA2/mLO5vpMZ2q78Nsn0m97wm28uiRnwO+/yOxigk= +github.com/Layr-Labs/protocol-apis v1.1.1-0.20250116155113-c22028af9e00 h1:7N3ta4X5YRygobnCuAAcKr4T76eUboXVcj+IGW0P2eA= +github.com/Layr-Labs/protocol-apis v1.1.1-0.20250116155113-c22028af9e00/go.mod h1:prNA2/mLO5vpMZ2q78Nsn0m97wm28uiRnwO+/yOxigk= +github.com/Layr-Labs/protocol-apis v1.1.1-0.20250116155715-919a0a9a27e5 h1:m/I5hGK4JpOE7OL7wYlKt9HwlCAgQ0SxeT3dNHfjzFY= +github.com/Layr-Labs/protocol-apis v1.1.1-0.20250116155715-919a0a9a27e5/go.mod h1:prNA2/mLO5vpMZ2q78Nsn0m97wm28uiRnwO+/yOxigk= +github.com/Layr-Labs/protocol-apis v1.1.1-0.20250121193118-8112817d1079 h1:B1b9ghilo70y4MJ7ZkF5w8BuPtslAUP2oE6vfzG6DBA= +github.com/Layr-Labs/protocol-apis v1.1.1-0.20250121193118-8112817d1079/go.mod h1:prNA2/mLO5vpMZ2q78Nsn0m97wm28uiRnwO+/yOxigk= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= diff --git a/pkg/rpcServer/protocolHandlers.go b/pkg/rpcServer/protocolHandlers.go index 9a829545..e6962b48 100644 --- a/pkg/rpcServer/protocolHandlers.go +++ b/pkg/rpcServer/protocolHandlers.go @@ -2,7 +2,10 @@ package rpcServer import ( "context" + "errors" + "github.com/Layr-Labs/protocol-apis/gen/protos/eigenlayer/sidecar/v1/common" protocolV1 "github.com/Layr-Labs/protocol-apis/gen/protos/eigenlayer/sidecar/v1/protocol" + "github.com/Layr-Labs/sidecar/pkg/service/types" ) func (rpc *RpcServer) GetRegisteredAvsForOperator(ctx context.Context, request *protocolV1.GetRegisteredAvsForOperatorRequest) (*protocolV1.GetRegisteredAvsForOperatorResponse, error) { @@ -21,8 +24,33 @@ func (rpc *RpcServer) GetOperatorDelegatedStakeForStrategy(ctx context.Context, } func (rpc *RpcServer) GetDelegatedStakersForOperator(ctx context.Context, request *protocolV1.GetDelegatedStakersForOperatorRequest) (*protocolV1.GetDelegatedStakersForOperatorResponse, error) { - //TODO implement me - panic("implement me") + operator := request.GetOperatorAddress() + if operator == "" { + return nil, errors.New("operator address is required") + } + pagination := types.NewDefaultPagination() + + if p := request.GetPagination(); p != nil { + pagination.Load(p.GetPageNumber(), p.GetPageSize()) + } + + delegatedStakers, err := rpc.protocolDataService.ListDelegatedStakersForOperator(operator, request.GetBlockHeight(), pagination) + if err != nil { + return nil, err + } + + var nextPage *common.Pagination + if uint32(len(delegatedStakers)) == pagination.PageSize { + nextPage = &common.Pagination{ + PageNumber: pagination.Page + 1, + PageSize: pagination.PageSize, + } + } + + return &protocolV1.GetDelegatedStakersForOperatorResponse{ + StakerAddresses: delegatedStakers, + NextPage: nextPage, + }, nil } func (rpc *RpcServer) GetStakerShares(ctx context.Context, request *protocolV1.GetStakerSharesRequest) (*protocolV1.GetStakerSharesResponse, error) { diff --git a/pkg/service/protocolDataService/protocol.go b/pkg/service/protocolDataService/protocol.go index 0f86838b..3a3a5810 100644 --- a/pkg/service/protocolDataService/protocol.go +++ b/pkg/service/protocolDataService/protocol.go @@ -27,6 +27,18 @@ func NewProtocolDataService( } } +func (pds *ProtocolDataService) getCurrentBlockHeightIfNotPresent(blockHeight uint64) (uint64, error) { + if blockHeight == 0 { + var currentBlock *storage.Block + res := pds.db.Model(&storage.Block{}).Order("number desc").First(¤tBlock) + if res.Error != nil { + return 0, res.Error + } + blockHeight = currentBlock.Number + } + return blockHeight, nil +} + func (pds *ProtocolDataService) ListRegisteredAVSsForOperator(operator string, blockHeight uint64) (interface{}, error) { return nil, nil } @@ -39,8 +51,50 @@ func (pds *ProtocolDataService) GetOperatorDelegatedStake(operator string, strat return nil, nil } -func (pds *ProtocolDataService) ListDelegatedStakersForOperator(operator string, blockHeight uint64, pagination types.Pagination) (interface{}, error) { - return nil, nil +func (pds *ProtocolDataService) ListDelegatedStakersForOperator(operator string, blockHeight uint64, pagination *types.Pagination) ([]string, error) { + bh, err := pds.getCurrentBlockHeightIfNotPresent(blockHeight) + if err != nil { + return nil, err + } + + query := ` + with staker_operator_delegations as ( + SELECT DISTINCT ON (staker) + staker, + operator, + delegated + FROM sidecar_mainnet_ethereum.staker_delegation_changes + WHERE operator = @operator + AND block_number <= @blockHeight + ORDER BY staker, block_number desc, log_index asc + ) + SELECT + sod.staker + from staker_operator_delegations as sod + where sod.delegated = true + ` + + queryParams := []interface{}{ + sql.Named("operator", operator), + sql.Named("blockHeight", bh), + } + + if pagination != nil { + query += ` LIMIT @limit` + queryParams = append(queryParams, sql.Named("limit", pagination.PageSize)) + + if pagination.Page > 0 { + query += ` OFFSET @offset` + queryParams = append(queryParams, sql.Named("offset", pagination.Page*pagination.PageSize)) + } + } + + var stakers []string + res := pds.db.Raw(query, queryParams...).Scan(&stakers) + if res.Error != nil { + return nil, res.Error + } + return stakers, nil } type StakerShares struct { @@ -60,13 +114,9 @@ type StakerShares struct { func (pds *ProtocolDataService) ListStakerShares(staker string, blockHeight uint64) ([]*StakerShares, error) { shares := make([]*StakerShares, 0) - if blockHeight == 0 { - var currentBlock *storage.Block - res := pds.db.Model(&storage.Block{}).Order("number desc").First(¤tBlock) - if res.Error != nil { - return nil, res.Error - } - blockHeight = currentBlock.Number + bh, err := pds.getCurrentBlockHeightIfNotPresent(blockHeight) + if err != nil { + return nil, err } query := ` @@ -116,7 +166,7 @@ func (pds *ProtocolDataService) ListStakerShares(staker string, blockHeight uint ` res := pds.db.Raw(query, sql.Named("staker", staker), - sql.Named("blockHeight", blockHeight), + sql.Named("blockHeight", bh), ).Scan(&shares) if res.Error != nil { return nil, res.Error diff --git a/pkg/service/types/pagination.go b/pkg/service/types/pagination.go index ab19fad6..3f6a047f 100644 --- a/pkg/service/types/pagination.go +++ b/pkg/service/types/pagination.go @@ -1,6 +1,23 @@ package types type Pagination struct { - Page int `json:"page"` - PageSize int `json:"page_size"` + Page uint32 `json:"page"` + PageSize uint32 `json:"page_size"` +} + +const DefaultPageSize = 100 +const DefaultPage = 0 + +func NewDefaultPagination() *Pagination { + return &Pagination{ + Page: DefaultPage, + PageSize: DefaultPageSize, + } +} + +func (p *Pagination) Load(pageNumber uint32, pageSize uint32) { + p.Page = pageNumber + if pageSize > 0 { + p.PageSize = pageSize + } }