code.vegaprotocol.io/vega@v0.79.0/datanode/api/server.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package api
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"io"
    22  	"net"
    23  	"net/http"
    24  	"strconv"
    25  	"time"
    26  
    27  	"code.vegaprotocol.io/vega/core/events"
    28  	"code.vegaprotocol.io/vega/datanode/candlesv2"
    29  	"code.vegaprotocol.io/vega/datanode/contextutil"
    30  	"code.vegaprotocol.io/vega/datanode/entities"
    31  	"code.vegaprotocol.io/vega/datanode/gateway"
    32  	"code.vegaprotocol.io/vega/datanode/networkhistory/segment"
    33  	"code.vegaprotocol.io/vega/datanode/ratelimit"
    34  	"code.vegaprotocol.io/vega/datanode/service"
    35  	"code.vegaprotocol.io/vega/libs/subscribers"
    36  	"code.vegaprotocol.io/vega/logging"
    37  	protoapi "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    38  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    39  	vegaprotoapi "code.vegaprotocol.io/vega/protos/vega/api/v1"
    40  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    41  
    42  	"github.com/fullstorydev/grpcui/standalone"
    43  	"golang.org/x/sync/errgroup"
    44  	"google.golang.org/grpc"
    45  	"google.golang.org/grpc/codes"
    46  	"google.golang.org/grpc/metadata"
    47  	"google.golang.org/grpc/peer"
    48  	"google.golang.org/grpc/reflection"
    49  	"google.golang.org/grpc/status"
    50  )
    51  
    52  // VolumeDiscountService ...
    53  //
    54  //go:generate go run github.com/golang/mock/mockgen -destination mocks/volume_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api VolumeDiscountService
    55  type VolumeDiscountService interface {
    56  	Stats(ctx context.Context, atEpoch *uint64, partyID *string, pagination entities.CursorPagination) ([]entities.FlattenVolumeDiscountStats, entities.PageInfo, error)
    57  }
    58  
    59  // EpochService
    60  //
    61  //go:generate go run github.com/golang/mock/mockgen -destination mocks/epoch_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api EpochService
    62  type EpochService interface {
    63  	GetCurrent(ctx context.Context) (entities.Epoch, error)
    64  	GetByBlock(ctx context.Context, height uint64) (entities.Epoch, error)
    65  	Get(ctx context.Context, ID uint64) (entities.Epoch, error)
    66  	GetAll(ctx context.Context) ([]entities.Epoch, error)
    67  }
    68  
    69  type ReferralSetService interface {
    70  	GetReferralSetStats(ctx context.Context, setID *entities.ReferralSetID, atEpoch *uint64, referee *entities.PartyID, pagination entities.CursorPagination) ([]entities.FlattenReferralSetStats, entities.PageInfo, error)
    71  	ListReferralSets(ctx context.Context, referralSetID *entities.ReferralSetID, referrer, referee *entities.PartyID, pagination entities.CursorPagination) ([]entities.ReferralSet, entities.PageInfo, error)
    72  	ListReferralSetReferees(ctx context.Context, referralSetID *entities.ReferralSetID, referrer, referee *entities.PartyID, pagination entities.CursorPagination, aggregationEpochs uint32) ([]entities.ReferralSetRefereeStats, entities.PageInfo, error)
    73  }
    74  
    75  // EventService ...
    76  //
    77  //go:generate go run github.com/golang/mock/mockgen -destination mocks/event_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api EventService
    78  type EventService interface {
    79  	ObserveEvents(ctx context.Context, retries int, eTypes []events.Type, batchSize int, filters ...subscribers.EventFilter) (<-chan []*eventspb.BusEvent, chan<- int)
    80  }
    81  
    82  // BlockService ...
    83  //
    84  //go:generate go run github.com/golang/mock/mockgen -destination mocks/block_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api BlockService
    85  type BlockService interface {
    86  	GetLastBlock(ctx context.Context) (entities.Block, error)
    87  }
    88  
    89  // NetworkHistoryService ...
    90  //
    91  // it would be nice to use go:generate go run github.com/golang/mock/mockgen -destination mocks/networkhistory_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api NetworkHistoryService
    92  // however it currently can't handle generic arguments and the generated code is not compilable without a bit of manual tweaking.
    93  type NetworkHistoryService interface {
    94  	GetHighestBlockHeightHistorySegment() (segment.Full, error)
    95  	ListAllHistorySegments() (segment.Segments[segment.Full], error)
    96  	FetchHistorySegment(ctx context.Context, historySegmentID string) (segment.Full, error)
    97  	GetActivePeerIPAddresses() []string
    98  	CopyHistorySegmentToFile(ctx context.Context, historySegmentID string, outFile string) error
    99  	GetHistorySegmentReader(ctx context.Context, historySegmentID string) (io.ReadSeekCloser, int64, error)
   100  	GetSwarmKeySeed() string
   101  	GetConnectedPeerAddresses() ([]string, error)
   102  	GetIpfsAddress() (string, error)
   103  	GetSwarmKey() string
   104  	GetBootstrapPeers() []string
   105  }
   106  
   107  // MarketsService ...
   108  //
   109  //go:generate go run github.com/golang/mock/mockgen -destination mocks/markets_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api MarketsService
   110  type MarketsService interface {
   111  	GetByID(ctx context.Context, marketID string) (entities.Market, error)
   112  	GetByTxHash(ctx context.Context, txHash entities.TxHash) ([]entities.Market, error)
   113  	GetAllPaged(ctx context.Context, marketID string, pagination entities.CursorPagination, includeSettled bool) ([]entities.Market, entities.PageInfo, error)
   114  	ListSuccessorMarkets(ctx context.Context, marketID string, childrenOnly bool, pagination entities.CursorPagination) ([]entities.SuccessorMarket, entities.PageInfo, error)
   115  }
   116  
   117  // MarketDataService ...
   118  //
   119  //go:generate go run github.com/golang/mock/mockgen -destination mocks/market_data_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api MarketDataService
   120  type MarketDataService interface {
   121  	GetMarketDataByID(ctx context.Context, marketID string) (entities.MarketData, error)
   122  	GetMarketsData(ctx context.Context) ([]entities.MarketData, error)
   123  	GetHistoricMarketData(ctx context.Context, marketID string, start, end *time.Time, pagination entities.Pagination) ([]entities.MarketData, entities.PageInfo, error)
   124  	ObserveMarketData(ctx context.Context, retries int, marketID []string) (<-chan []*entities.MarketData, uint64)
   125  }
   126  
   127  // RiskFactorService ...
   128  //
   129  //go:generate go run github.com/golang/mock/mockgen -destination mocks/risk_factor_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api RiskFactorService
   130  type RiskFactorService interface {
   131  	GetMarketRiskFactors(ctx context.Context, marketID string) (entities.RiskFactor, error)
   132  }
   133  
   134  // Asset service ...
   135  //
   136  //go:generate go run github.com/golang/mock/mockgen -destination mocks/asset_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api AssetService
   137  type AssetService interface {
   138  	GetByID(ctx context.Context, id string) (entities.Asset, error)
   139  	GetByTxHash(ctx context.Context, txHash entities.TxHash) ([]entities.Asset, error)
   140  	GetAll(ctx context.Context) ([]entities.Asset, error)
   141  	GetAllWithCursorPagination(ctx context.Context, pagination entities.CursorPagination) ([]entities.Asset, entities.PageInfo, error)
   142  }
   143  
   144  //go:generate go run github.com/golang/mock/mockgen -destination mocks/amm_service_mock.go -package mocks code.vegaprotocol.io/vega/datanode/api AMMService
   145  type AMMService interface {
   146  	GetSubKeysForParties(ctx context.Context, partyIDs []string, marketIDs []string) ([]string, error)
   147  	ListAll(ctx context.Context, liveOnly bool, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   148  	ListByMarket(ctx context.Context, marketID string, liveOnly bool, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   149  	ListByParty(ctx context.Context, partyID string, liveOnly bool, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   150  	ListByPool(ctx context.Context, poolID string, liveOnly bool, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   151  	ListByStatus(ctx context.Context, status entities.AMMStatus, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   152  	ListBySubAccount(ctx context.Context, ammPartyID string, liveOnly bool, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   153  	ListByPartyMarketStatus(ctx context.Context, party, market *string, status *entities.AMMStatus, liveOnly bool, pagination entities.CursorPagination) ([]entities.AMMPool, entities.PageInfo, error)
   154  }
   155  
   156  type PartyStatsSvc interface {
   157  	GetPartyStats(ctx context.Context, partyID string, marketIDs []string) (*v2.GetPartyDiscountStatsResponse, error)
   158  }
   159  
   160  // GRPCServer represent the grpc api provided by the vega node.
   161  type GRPCServer struct {
   162  	Config
   163  	log                   *logging.Logger
   164  	srv                   *grpc.Server
   165  	vegaCoreServiceClient CoreServiceClient
   166  
   167  	eventService                        *subscribers.Service
   168  	coreProxySvc                        *coreProxyService
   169  	orderService                        *service.Order
   170  	candleService                       *candlesv2.Svc
   171  	networkLimitsService                *service.NetworkLimits
   172  	marketDataService                   *service.MarketData
   173  	tradeService                        *service.Trade
   174  	AssetService                        AssetService
   175  	accountService                      *service.Account
   176  	rewardService                       *service.Reward
   177  	marketsService                      *service.Markets
   178  	delegationService                   *service.Delegation
   179  	epochService                        *service.Epoch
   180  	depositService                      *service.Deposit
   181  	withdrawalService                   *service.Withdrawal
   182  	governanceService                   *service.Governance
   183  	riskFactorService                   *service.RiskFactor
   184  	riskService                         *service.Risk
   185  	networkParameterService             *service.NetworkParameter
   186  	blockService                        BlockService
   187  	partyService                        *service.Party
   188  	checkpointService                   *service.Checkpoint
   189  	oracleSpecService                   *service.OracleSpec
   190  	oracleDataService                   *service.OracleData
   191  	liquidityProvisionService           *service.LiquidityProvision
   192  	positionService                     *service.Position
   193  	transferService                     *service.Transfer
   194  	stakeLinkingService                 *service.StakeLinking
   195  	notaryService                       *service.Notary
   196  	multiSigService                     *service.MultiSig
   197  	keyRotationService                  *service.KeyRotations
   198  	ethereumKeyRotationService          *service.EthereumKeyRotation
   199  	nodeService                         *service.Node
   200  	marketDepthService                  *service.MarketDepth
   201  	ledgerService                       *service.Ledger
   202  	protocolUpgradeService              *service.ProtocolUpgrade
   203  	networkHistoryService               NetworkHistoryService
   204  	coreSnapshotService                 *service.SnapshotData
   205  	stopOrderService                    *service.StopOrders
   206  	fundingPeriodService                *service.FundingPeriods
   207  	partyActivityStreak                 *service.PartyActivityStreak
   208  	referralProgramService              *service.ReferralPrograms
   209  	referralSetsService                 *service.ReferralSets
   210  	teamsService                        *service.Teams
   211  	vestingStatsService                 *service.VestingStats
   212  	FeesStatsService                    *service.FeesStats
   213  	fundingPaymentService               *service.FundingPayment
   214  	volumeDiscountStatsService          *service.VolumeDiscountStats
   215  	volumeDiscountProgramService        *service.VolumeDiscountPrograms
   216  	paidLiquidityFeesStatsService       *service.PaidLiquidityFeesStats
   217  	partyLockedBalances                 *service.PartyLockedBalances
   218  	partyVestingBalances                *service.PartyVestingBalances
   219  	transactionResults                  *service.TransactionResults
   220  	gamesService                        *service.Games
   221  	marginModesService                  *service.MarginModes
   222  	timeWeightedNotionalPositionService *service.TimeWeightedNotionalPosition
   223  	gameScoreService                    *service.GameScore
   224  	ammPoolService                      *service.AMMPools
   225  	volumeRebateStatsService            *service.VolumeRebateStats
   226  	volumeRebateProgramService          *service.VolumeRebatePrograms
   227  
   228  	eventObserver *eventObserver
   229  
   230  	// used in order to gracefully close streams
   231  	ctx   context.Context
   232  	cfunc context.CancelFunc
   233  
   234  	trustedProxies map[string]struct{}
   235  }
   236  
   237  // NewGRPCServer create a new instance of the GPRC api for the vega node.
   238  func NewGRPCServer(
   239  	log *logging.Logger,
   240  	config Config,
   241  	coreServiceClient CoreServiceClient,
   242  	eventService *subscribers.Service,
   243  	orderService *service.Order,
   244  	networkLimitsService *service.NetworkLimits,
   245  	marketDataService *service.MarketData,
   246  	tradeService *service.Trade,
   247  	assetService *service.Asset,
   248  	accountService *service.Account,
   249  	rewardService *service.Reward,
   250  	marketsService *service.Markets,
   251  	delegationService *service.Delegation,
   252  	epochService *service.Epoch,
   253  	depositService *service.Deposit,
   254  	withdrawalService *service.Withdrawal,
   255  	governanceService *service.Governance,
   256  	riskFactorService *service.RiskFactor,
   257  	riskService *service.Risk,
   258  	networkParameterService *service.NetworkParameter,
   259  	blockService BlockService,
   260  	checkpointService *service.Checkpoint,
   261  	partyService *service.Party,
   262  	candleService *candlesv2.Svc,
   263  	oracleSpecService *service.OracleSpec,
   264  	oracleDataService *service.OracleData,
   265  	liquidityProvisionService *service.LiquidityProvision,
   266  	positionService *service.Position,
   267  	transferService *service.Transfer,
   268  	stakeLinkingService *service.StakeLinking,
   269  	notaryService *service.Notary,
   270  	multiSigService *service.MultiSig,
   271  	keyRotationService *service.KeyRotations,
   272  	ethereumKeyRotationService *service.EthereumKeyRotation,
   273  	nodeService *service.Node,
   274  	marketDepthService *service.MarketDepth,
   275  	ledgerService *service.Ledger,
   276  	protocolUpgradeService *service.ProtocolUpgrade,
   277  	networkHistoryService NetworkHistoryService,
   278  	coreSnapshotService *service.SnapshotData,
   279  	stopOrderService *service.StopOrders,
   280  	fundingPeriodService *service.FundingPeriods,
   281  	partyActivityStreak *service.PartyActivityStreak,
   282  	referralProgramService *service.ReferralPrograms,
   283  	referralSetsService *service.ReferralSets,
   284  	teamsService *service.Teams,
   285  	vestingStatsService *service.VestingStats,
   286  	FeesStatsService *service.FeesStats,
   287  	fundingPaymentService *service.FundingPayment,
   288  	volumeDiscountStatsService *service.VolumeDiscountStats,
   289  	volumeDiscountProgramService *service.VolumeDiscountPrograms,
   290  	paidLiquidityFeesStatsService *service.PaidLiquidityFeesStats,
   291  	partyLockedBalances *service.PartyLockedBalances,
   292  	partyVestingBalances *service.PartyVestingBalances,
   293  	transactionResults *service.TransactionResults,
   294  	gameService *service.Games,
   295  	marginModesService *service.MarginModes,
   296  	timeWeightedNotionalPositionService *service.TimeWeightedNotionalPosition,
   297  	gameScoreService *service.GameScore,
   298  	ammPoolService *service.AMMPools,
   299  	volumeRebateStatsService *service.VolumeRebateStats,
   300  	volumeRebateProgramsService *service.VolumeRebatePrograms,
   301  ) *GRPCServer {
   302  	// setup logger
   303  	log = log.Named(namedLogger)
   304  	log.SetLevel(config.Level.Get())
   305  	ctx, cfunc := context.WithCancel(context.Background())
   306  	tps := make(map[string]struct{}, len(config.RateLimit.TrustedProxies))
   307  	for _, ip := range config.RateLimit.TrustedProxies {
   308  		tps[ip] = struct{}{}
   309  	}
   310  
   311  	return &GRPCServer{
   312  		log:                                 log,
   313  		Config:                              config,
   314  		vegaCoreServiceClient:               coreServiceClient,
   315  		eventService:                        eventService,
   316  		orderService:                        orderService,
   317  		networkLimitsService:                networkLimitsService,
   318  		tradeService:                        tradeService,
   319  		AssetService:                        assetService,
   320  		accountService:                      accountService,
   321  		rewardService:                       rewardService,
   322  		marketsService:                      marketsService,
   323  		delegationService:                   delegationService,
   324  		epochService:                        epochService,
   325  		depositService:                      depositService,
   326  		withdrawalService:                   withdrawalService,
   327  		multiSigService:                     multiSigService,
   328  		governanceService:                   governanceService,
   329  		riskFactorService:                   riskFactorService,
   330  		networkParameterService:             networkParameterService,
   331  		blockService:                        blockService,
   332  		checkpointService:                   checkpointService,
   333  		partyService:                        partyService,
   334  		candleService:                       candleService,
   335  		oracleSpecService:                   oracleSpecService,
   336  		oracleDataService:                   oracleDataService,
   337  		liquidityProvisionService:           liquidityProvisionService,
   338  		positionService:                     positionService,
   339  		transferService:                     transferService,
   340  		stakeLinkingService:                 stakeLinkingService,
   341  		notaryService:                       notaryService,
   342  		keyRotationService:                  keyRotationService,
   343  		ethereumKeyRotationService:          ethereumKeyRotationService,
   344  		nodeService:                         nodeService,
   345  		marketDepthService:                  marketDepthService,
   346  		riskService:                         riskService,
   347  		marketDataService:                   marketDataService,
   348  		ledgerService:                       ledgerService,
   349  		protocolUpgradeService:              protocolUpgradeService,
   350  		networkHistoryService:               networkHistoryService,
   351  		coreSnapshotService:                 coreSnapshotService,
   352  		stopOrderService:                    stopOrderService,
   353  		fundingPeriodService:                fundingPeriodService,
   354  		partyActivityStreak:                 partyActivityStreak,
   355  		referralProgramService:              referralProgramService,
   356  		referralSetsService:                 referralSetsService,
   357  		teamsService:                        teamsService,
   358  		vestingStatsService:                 vestingStatsService,
   359  		FeesStatsService:                    FeesStatsService,
   360  		fundingPaymentService:               fundingPaymentService,
   361  		volumeDiscountStatsService:          volumeDiscountStatsService,
   362  		volumeDiscountProgramService:        volumeDiscountProgramService,
   363  		paidLiquidityFeesStatsService:       paidLiquidityFeesStatsService,
   364  		partyLockedBalances:                 partyLockedBalances,
   365  		partyVestingBalances:                partyVestingBalances,
   366  		transactionResults:                  transactionResults,
   367  		gamesService:                        gameService,
   368  		marginModesService:                  marginModesService,
   369  		timeWeightedNotionalPositionService: timeWeightedNotionalPositionService,
   370  		gameScoreService:                    gameScoreService,
   371  		ammPoolService:                      ammPoolService,
   372  		volumeRebateStatsService:            volumeRebateStatsService,
   373  		volumeRebateProgramService:          volumeRebateProgramsService,
   374  		eventObserver: &eventObserver{
   375  			log:          log,
   376  			eventService: eventService,
   377  			Config:       config,
   378  		},
   379  		ctx:            ctx,
   380  		cfunc:          cfunc,
   381  		trustedProxies: tps,
   382  	}
   383  }
   384  
   385  // ReloadConf update the internal configuration of the GRPC server.
   386  func (g *GRPCServer) ReloadConf(cfg Config) {
   387  	g.log.Info("reloading configuration")
   388  	if g.log.GetLevel() != cfg.Level.Get() {
   389  		g.log.Info("updating log level",
   390  			logging.String("old", g.log.GetLevel().String()),
   391  			logging.String("new", cfg.Level.String()),
   392  		)
   393  		g.log.SetLevel(cfg.Level.Get())
   394  	}
   395  	tps := make(map[string]struct{}, len(cfg.RateLimit.TrustedProxies))
   396  	for _, ip := range cfg.RateLimit.TrustedProxies {
   397  		tps[ip] = struct{}{}
   398  	}
   399  
   400  	// TODO(): not updating the actual server for now, may need to look at this later
   401  	// e.g restart the http server on another port or whatever
   402  	g.Config = cfg
   403  	g.trustedProxies = tps
   404  }
   405  
   406  func (g *GRPCServer) ipFromContext(ctx context.Context, method string, log *logging.Logger) (string, error) {
   407  	// first check if the request is forwarded from our restproxy
   408  	tps := g.trustedProxies
   409  	if len(tps) > 0 {
   410  		// get the metadata
   411  		if md, ok := metadata.FromIncomingContext(ctx); ok {
   412  			// if trusted proxies are specified, the XFF header will be used to rate-limit the IP
   413  			// for which the request is forwarded. If no proxies are specified, or no trusted proxies
   414  			// are found, the peer is rate limited.
   415  			if forwardedFor, ok := md["x-forwarded-for"]; ok && len(forwardedFor) >= 2 {
   416  				// check the proxies for trusted
   417  				for _, pip := range forwardedFor[1:] {
   418  					// trusted proxy found, return
   419  					if _, ok := tps[pip]; ok {
   420  						log.Debug("grpc request x-forwarded-for",
   421  							logging.String("method", method),
   422  							logging.String("remote-ip-addr", forwardedFor[0]),
   423  						)
   424  						return forwardedFor[0], nil
   425  					}
   426  				}
   427  			}
   428  		}
   429  	}
   430  
   431  	// if the request is not forwarded let's get it from the peer infos
   432  	p, ok := peer.FromContext(ctx)
   433  	if ok && p != nil {
   434  		log.Debug("grpc peer client request",
   435  			logging.String("method", method),
   436  			logging.String("remote-ip-addr", p.Addr.String()))
   437  		return p.Addr.String(), nil
   438  	}
   439  
   440  	return "", nil
   441  }
   442  
   443  func (g *GRPCServer) remoteAddrInterceptor(log *logging.Logger) grpc.UnaryServerInterceptor {
   444  	return func(
   445  		ctx context.Context,
   446  		req interface{},
   447  		info *grpc.UnaryServerInfo,
   448  		handler grpc.UnaryHandler,
   449  	) (resp interface{}, err error) {
   450  		ip, err := g.ipFromContext(ctx, info.FullMethod, log)
   451  		if err != nil {
   452  			return nil, status.Error(codes.PermissionDenied, err.Error())
   453  		}
   454  
   455  		ctx = contextutil.WithRemoteIPAddr(ctx, ip)
   456  
   457  		// Calls the handler
   458  		h, err := handler(ctx, req)
   459  
   460  		log.Debug("Invoked RPC call",
   461  			logging.String("method", info.FullMethod),
   462  			logging.Error(err),
   463  		)
   464  
   465  		return h, err
   466  	}
   467  }
   468  
   469  func headersInterceptor(
   470  	getLastBlock func(context.Context) (entities.Block, error),
   471  	log *logging.Logger,
   472  ) grpc.UnaryServerInterceptor {
   473  	return func(
   474  		ctx context.Context,
   475  		req interface{},
   476  		info *grpc.UnaryServerInfo,
   477  		handler grpc.UnaryHandler,
   478  	) (interface{}, error) {
   479  		var (
   480  			height    int64
   481  			timestamp int64
   482  		)
   483  
   484  		block, bErr := getLastBlock(ctx)
   485  		if bErr != nil {
   486  			log.Debug("failed to get last block", logging.Error(bErr))
   487  		} else {
   488  			height = block.Height
   489  			timestamp = block.VegaTime.UnixNano()
   490  		}
   491  
   492  		for _, h := range []metadata.MD{
   493  			// Deprecated: use 'X-Block-Height' and 'X-Block-Timestamp' instead to determine if data is fresh.
   494  			metadata.Pairs("X-Block-Height", strconv.FormatInt(height, 10)),
   495  			metadata.Pairs("X-Block-Timestamp", strconv.FormatInt(timestamp, 10)),
   496  		} {
   497  			if errH := grpc.SetHeader(ctx, h); errH != nil {
   498  				log.Error("failed to set header", logging.Error(errH))
   499  			}
   500  		}
   501  
   502  		return handler(ctx, req)
   503  	}
   504  }
   505  
   506  func (g *GRPCServer) getTCPListener() (net.Listener, error) {
   507  	ip := g.IP
   508  	port := strconv.Itoa(g.Port)
   509  
   510  	g.log.Info("Starting gRPC based API", logging.String("addr", ip), logging.String("port", port))
   511  
   512  	tpcLis, err := net.Listen("tcp", net.JoinHostPort(ip, port))
   513  	if err != nil {
   514  		return nil, err
   515  	}
   516  
   517  	return tpcLis, nil
   518  }
   519  
   520  // Start starts the grpc server.
   521  // Uses default TCP listener if no provided.
   522  func (g *GRPCServer) Start(ctx context.Context, lis net.Listener) error {
   523  	if lis == nil {
   524  		tpcLis, err := g.getTCPListener()
   525  		if err != nil {
   526  			return err
   527  		}
   528  
   529  		lis = tpcLis
   530  	}
   531  
   532  	subscriptionRateLimiter := gateway.NewSubscriptionRateLimiter(g.log, g.Config.MaxSubscriptionPerClient)
   533  
   534  	rateLimit := ratelimit.NewFromConfig(&g.RateLimit, g.log)
   535  	intercept := grpc.ChainUnaryInterceptor(
   536  		g.remoteAddrInterceptor(g.log),
   537  		headersInterceptor(g.blockService.GetLastBlock, g.log),
   538  		rateLimit.GRPCInterceptor,
   539  	)
   540  
   541  	streamIntercept := grpc.StreamInterceptor(subscriptionRateLimiter.WithGrpcInterceptor(g.ipFromContext))
   542  	partyDiscountStats := service.NewPartyStatsService(g.epochService,
   543  		g.referralSetsService.ReferralSets,
   544  		g.volumeDiscountStatsService,
   545  		g.volumeRebateStatsService,
   546  		g.marketsService,
   547  		g.referralProgramService.ReferralPrograms,
   548  		g.volumeDiscountProgramService.VolumeDiscountPrograms,
   549  		g.volumeRebateProgramService.VolumeRebatePrograms,
   550  	)
   551  
   552  	g.srv = grpc.NewServer(intercept, streamIntercept)
   553  
   554  	coreProxySvc := &coreProxyService{
   555  		conf:              g.Config,
   556  		coreServiceClient: g.vegaCoreServiceClient,
   557  		eventObserver:     g.eventObserver,
   558  	}
   559  	g.coreProxySvc = coreProxySvc
   560  	vegaprotoapi.RegisterCoreServiceServer(g.srv, coreProxySvc)
   561  
   562  	tradingDataSvcV2 := &TradingDataServiceV2{
   563  		config:               g.Config,
   564  		log:                  g.log,
   565  		orderService:         g.orderService,
   566  		networkLimitsService: g.networkLimitsService,
   567  		MarketDataService:    g.marketDataService,
   568  		tradeService:         g.tradeService,
   569  		multiSigService:      g.multiSigService,
   570  		notaryService:        g.notaryService,
   571  		AssetService:         g.AssetService,
   572  		candleService:        g.candleService,
   573  		MarketsService:       g.marketsService,
   574  
   575  		partyService:                  g.partyService,
   576  		riskService:                   g.riskService,
   577  		positionService:               g.positionService,
   578  		AccountService:                g.accountService,
   579  		RewardService:                 g.rewardService,
   580  		depositService:                g.depositService,
   581  		withdrawalService:             g.withdrawalService,
   582  		oracleSpecService:             g.oracleSpecService,
   583  		oracleDataService:             g.oracleDataService,
   584  		liquidityProvisionService:     g.liquidityProvisionService,
   585  		governanceService:             g.governanceService,
   586  		transfersService:              g.transferService,
   587  		delegationService:             g.delegationService,
   588  		marketDepthService:            g.marketDepthService,
   589  		nodeService:                   g.nodeService,
   590  		EpochService:                  g.epochService,
   591  		RiskFactorService:             g.riskFactorService,
   592  		networkParameterService:       g.networkParameterService,
   593  		checkpointService:             g.checkpointService,
   594  		stakeLinkingService:           g.stakeLinkingService,
   595  		eventService:                  g.eventService,
   596  		ledgerService:                 g.ledgerService,
   597  		keyRotationService:            g.keyRotationService,
   598  		ethereumKeyRotationService:    g.ethereumKeyRotationService,
   599  		blockService:                  g.blockService,
   600  		protocolUpgradeService:        g.protocolUpgradeService,
   601  		NetworkHistoryService:         g.networkHistoryService,
   602  		coreSnapshotService:           g.coreSnapshotService,
   603  		stopOrderService:              g.stopOrderService,
   604  		fundingPeriodService:          g.fundingPeriodService,
   605  		partyActivityStreak:           g.partyActivityStreak,
   606  		referralProgramService:        g.referralProgramService,
   607  		ReferralSetsService:           g.referralSetsService,
   608  		teamsService:                  g.teamsService,
   609  		feesStatsService:              g.FeesStatsService,
   610  		fundingPaymentService:         g.fundingPaymentService,
   611  		VolumeDiscountStatsService:    g.volumeDiscountStatsService,
   612  		volumeDiscountProgramService:  g.volumeDiscountProgramService,
   613  		paidLiquidityFeesStatsService: g.paidLiquidityFeesStatsService,
   614  		partyLockedBalances:           g.partyLockedBalances,
   615  		partyVestingBalances:          g.partyVestingBalances,
   616  		vestingStats:                  g.vestingStatsService,
   617  		transactionResults:            g.transactionResults,
   618  		gamesService:                  g.gamesService,
   619  		marginModesService:            g.marginModesService,
   620  		twNotionalPositionService:     g.timeWeightedNotionalPositionService,
   621  		gameScoreService:              g.gameScoreService,
   622  		AMMPoolService:                g.ammPoolService,
   623  		volumeRebateStatsService:      g.volumeRebateStatsService,
   624  		volumeRebateProgramService:    g.volumeRebateProgramService,
   625  		partyDiscountStats:            partyDiscountStats,
   626  	}
   627  
   628  	protoapi.RegisterTradingDataServiceServer(g.srv, tradingDataSvcV2)
   629  
   630  	eg, ctx := errgroup.WithContext(ctx)
   631  
   632  	if g.Reflection || g.WebUIEnabled {
   633  		reflection.Register(g.srv)
   634  	}
   635  
   636  	eg.Go(func() error {
   637  		<-ctx.Done()
   638  		g.stop()
   639  		return ctx.Err()
   640  	})
   641  
   642  	eg.Go(func() error {
   643  		return g.srv.Serve(lis)
   644  	})
   645  
   646  	if g.WebUIEnabled {
   647  		g.startWebUI(ctx)
   648  	}
   649  
   650  	return eg.Wait()
   651  }
   652  
   653  func (g *GRPCServer) stop() {
   654  	if g.srv == nil {
   655  		return
   656  	}
   657  
   658  	done := make(chan struct{})
   659  	go func() {
   660  		g.log.Info("Gracefully stopping gRPC based API")
   661  		g.srv.GracefulStop()
   662  		done <- struct{}{}
   663  	}()
   664  
   665  	select {
   666  	case <-done:
   667  	case <-time.After(10 * time.Second):
   668  		g.log.Info("Force stopping gRPC based API")
   669  		g.srv.Stop()
   670  	}
   671  }
   672  
   673  func (g *GRPCServer) startWebUI(ctx context.Context) {
   674  	cc, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", g.Port), grpc.WithInsecure())
   675  	if err != nil {
   676  		g.log.Error("failed to create client to local grpc server", logging.Error(err))
   677  		return
   678  	}
   679  
   680  	uiHandler, err := standalone.HandlerViaReflection(ctx, cc, "vega data node")
   681  	if err != nil {
   682  		g.log.Error("failed to create grpc-ui server", logging.Error(err))
   683  		return
   684  	}
   685  
   686  	uiListener, err := net.Listen("tcp", net.JoinHostPort(g.IP, strconv.Itoa(g.WebUIPort)))
   687  	if err != nil {
   688  		g.log.Error("failed to open listen socket on port", logging.Int("port", g.WebUIPort), logging.Error(err))
   689  		return
   690  	}
   691  
   692  	g.log.Info("Starting gRPC Web UI", logging.String("addr", g.IP), logging.Int("port", g.WebUIPort))
   693  	go http.Serve(uiListener, uiHandler)
   694  }