diff --git a/rpc/middleware.go b/rpc/middleware.go new file mode 100644 index 0000000..fac91cb --- /dev/null +++ b/rpc/middleware.go @@ -0,0 +1,92 @@ +package rpc + +import ( + "context" + "github.com/pkg/errors" + "github.com/qubic/go-archiver/protobuff" + "github.com/qubic/go-archiver/validator/tick" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type ProcessedTicksStore interface { + GetLastProcessedTick(ctx context.Context) (*protobuff.ProcessedTick, error) + GetProcessedTickIntervals(ctx context.Context) ([]*protobuff.ProcessedTickIntervalsPerEpoch, error) +} + +type TickWithinBoundsInterceptor struct { + store ProcessedTicksStore +} + +func NewTickWithinBoundsInterceptor(store ProcessedTicksStore) *TickWithinBoundsInterceptor { + return &TickWithinBoundsInterceptor{store: store} +} + +func (twb *TickWithinBoundsInterceptor) GetInterceptor(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + + var err error + + switch request := req.(type) { + + case *protobuff.GetTickRequestV2: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + case *protobuff.GetTickTransactionsRequest: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + case *protobuff.GetTickDataRequest: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + case *protobuff.GetQuorumTickDataRequest: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + case *protobuff.GetTickApprovedTransactionsRequest: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + case *protobuff.GetChainHashRequest: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + case *protobuff.GetTickTransactionsRequestV2: + err = twb.checkTickWithinArchiverIntervals(ctx, request.TickNumber) + + default: + break + } + + if err != nil { + return nil, errors.Wrapf(err, "invalid tick number") + } + + h, err := handler(ctx, req) + + return h, err +} + +func (twb *TickWithinBoundsInterceptor) checkTickWithinArchiverIntervals(ctx context.Context, tickNumber uint32) error { + + lastProcessedTick, err := twb.store.GetLastProcessedTick(ctx) + if err != nil { + return status.Errorf(codes.Internal, "failed to get last processed tick") + } + + if tickNumber > lastProcessedTick.TickNumber { + st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", tickNumber, lastProcessedTick.TickNumber) + st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) + if err != nil { + return status.Errorf(codes.Internal, "creating custom status") + } + return st.Err() + } + + processedTickIntervalsPerEpoch, err := twb.store.GetProcessedTickIntervals(ctx) + if err != nil { + return status.Errorf(codes.Internal, "getting processed tick intervals per epoch") + } + + wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(tickNumber, processedTickIntervalsPerEpoch) + if wasSkipped == true { + st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", tickNumber, nextAvailableTick) + st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) + if err != nil { + return status.Errorf(codes.Internal, "creating custom status") + } + return st.Err() + } + + return nil +} diff --git a/rpc/rpc_server.go b/rpc/rpc_server.go index b0c2cba..91a58af 100644 --- a/rpc/rpc_server.go +++ b/rpc/rpc_server.go @@ -82,36 +82,6 @@ func getTransactionInfo(ctx context.Context, pebbleStore *store.PebbleStore, tra } func (s *Server) GetTickData(ctx context.Context, req *protobuff.GetTickDataRequest) (*protobuff.GetTickDataResponse, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - tickData, err := s.store.GetTickData(ctx, req.TickNumber) if err != nil { if errors.Is(err, store.ErrNotFound) { @@ -131,35 +101,6 @@ func (s *Server) GetTickData(ctx context.Context, req *protobuff.GetTickDataRequ return &protobuff.GetTickDataResponse{TickData: tickData}, nil } func (s *Server) GetTickTransactions(ctx context.Context, req *protobuff.GetTickTransactionsRequest) (*protobuff.GetTickTransactionsResponse, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } txs, err := s.store.GetTickTransactions(ctx, req.TickNumber) if err != nil { @@ -173,35 +114,6 @@ func (s *Server) GetTickTransactions(ctx context.Context, req *protobuff.GetTick } func (s *Server) GetTickTransferTransactions(ctx context.Context, req *protobuff.GetTickTransactionsRequest) (*protobuff.GetTickTransactionsResponse, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } txs, err := s.store.GetTickTransferTransactions(ctx, req.TickNumber) if err != nil { @@ -474,35 +386,6 @@ func (s *Server) GetTransferTransactionsPerTick(ctx context.Context, req *protob } func (s *Server) GetTickApprovedTransactions(ctx context.Context, req *protobuff.GetTickApprovedTransactionsRequest) (*protobuff.GetTickApprovedTransactionsResponse, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } tts, err := s.store.GetTickTransactionsStatus(ctx, uint64(req.TickNumber)) if err != nil { @@ -638,9 +521,13 @@ func (s *Server) GetStoreHash(ctx context.Context, req *protobuff.GetChainHashRe } func (s *Server) Start() error { + + tickInBoundsInterception := NewTickWithinBoundsInterceptor(s.store) + srv := grpc.NewServer( grpc.MaxRecvMsgSize(600*1024*1024), grpc.MaxSendMsgSize(600*1024*1024), + grpc.UnaryInterceptor(tickInBoundsInterception.GetInterceptor), ) protobuff.RegisterArchiveServiceServer(srv, s) reflection.Register(srv) diff --git a/rpc/v2_endpoints.go b/rpc/v2_endpoints.go index 79b30c2..52a6aa3 100644 --- a/rpc/v2_endpoints.go +++ b/rpc/v2_endpoints.go @@ -5,7 +5,6 @@ import ( "context" "encoding/hex" "github.com/cockroachdb/pebble" - "github.com/qubic/go-archiver/validator/tick" "slices" "github.com/pkg/errors" @@ -53,35 +52,6 @@ func (s *Server) GetTickTransactionsV2(ctx context.Context, req *protobuff.GetTi } func (s *Server) GetAllTickTransactionsV2(ctx context.Context, req *protobuff.GetTickRequestV2) (*protobuff.GetTickTransactionsResponseV2, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } txs, err := s.store.GetTickTransactions(ctx, req.TickNumber) if err != nil { @@ -112,35 +82,6 @@ func (s *Server) GetAllTickTransactionsV2(ctx context.Context, req *protobuff.Ge } func (s *Server) GetTransferTickTransactionsV2(ctx context.Context, req *protobuff.GetTickRequestV2) (*protobuff.GetTickTransactionsResponseV2, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } txs, err := s.store.GetTickTransferTransactions(ctx, req.TickNumber) if err != nil { @@ -171,35 +112,6 @@ func (s *Server) GetTransferTickTransactionsV2(ctx context.Context, req *protobu } func (s *Server) GetApprovedTickTransactionsV2(ctx context.Context, req *protobuff.GetTickRequestV2) (*protobuff.GetTickTransactionsResponseV2, error) { - lastProcessedTick, err := s.store.GetLastProcessedTick(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting last processed tick: %v", err) - } - if req.TickNumber > lastProcessedTick.TickNumber { - st := status.Newf(codes.FailedPrecondition, "requested tick number %d is greater than last processed tick %d", req.TickNumber, lastProcessedTick.TickNumber) - st, err = st.WithDetails(&protobuff.LastProcessedTick{LastProcessedTick: lastProcessedTick.TickNumber}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } - - processedTickIntervalsPerEpoch, err := s.store.GetProcessedTickIntervals(ctx) - if err != nil { - return nil, status.Errorf(codes.Internal, "getting processed tick intervals per epoch") - } - - wasSkipped, nextAvailableTick := tick.WasSkippedByArchive(req.TickNumber, processedTickIntervalsPerEpoch) - if wasSkipped == true { - st := status.Newf(codes.OutOfRange, "provided tick number %d was skipped by the system, next available tick is %d", req.TickNumber, nextAvailableTick) - st, err = st.WithDetails(&protobuff.NextAvailableTick{NextTickNumber: nextAvailableTick}) - if err != nil { - return nil, status.Errorf(codes.Internal, "creating custom status") - } - - return nil, st.Err() - } txs, err := s.store.GetTickTransferTransactions(ctx, req.TickNumber) if err != nil {