- Introduced a new Diagnostics struct to capture transaction visibility state and activity state. - Updated BuildSnapshot function to return diagnostics alongside snapshot, completeness, and sampling. - Enhanced test cases to validate the new diagnostics data. - Updated frontend components to utilize the new diagnostics information for improved user feedback on freshness context. This change improves the observability of transaction activity and enhances the user experience by providing clearer insights into the freshness of data.
150 lines
5.6 KiB
Go
150 lines
5.6 KiB
Go
package rest
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/explorer/backend/api/freshness"
|
|
"github.com/explorer/backend/api/middleware"
|
|
"github.com/explorer/backend/api/track1"
|
|
"github.com/explorer/backend/api/track2"
|
|
"github.com/explorer/backend/api/track3"
|
|
"github.com/explorer/backend/api/track4"
|
|
"github.com/explorer/backend/libs/go-rpc-gateway"
|
|
)
|
|
|
|
// SetupTrackRoutes sets up track-specific routes with proper middleware
|
|
func (s *Server) SetupTrackRoutes(mux *http.ServeMux, authMiddleware *middleware.AuthMiddleware) {
|
|
// Initialize Track 1 (RPC Gateway) using reusable lib
|
|
rpcURL := os.Getenv("RPC_URL")
|
|
if rpcURL == "" {
|
|
rpcURL = "http://localhost:8545"
|
|
}
|
|
|
|
var cache gateway.Cache
|
|
if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
|
|
if c, err := gateway.NewRedisCache(redisURL); err == nil {
|
|
cache = c
|
|
}
|
|
}
|
|
if cache == nil {
|
|
cache = gateway.NewInMemoryCache()
|
|
}
|
|
|
|
rateLimitConfig := gateway.RateLimitConfig{
|
|
RequestsPerSecond: 10,
|
|
RequestsPerMinute: 100,
|
|
BurstSize: 20,
|
|
}
|
|
var rateLimiter gateway.RateLimiter
|
|
if redisURL := os.Getenv("REDIS_URL"); redisURL != "" {
|
|
if rl, err := gateway.NewRedisRateLimiter(redisURL, rateLimitConfig); err == nil {
|
|
rateLimiter = rl
|
|
}
|
|
}
|
|
if rateLimiter == nil {
|
|
rateLimiter = gateway.NewInMemoryRateLimiter(rateLimitConfig)
|
|
}
|
|
|
|
rpcGateway := gateway.NewRPCGateway(rpcURL, cache, rateLimiter)
|
|
track1Server := track1.NewServer(rpcGateway, func(ctx context.Context) (*freshness.Snapshot, *freshness.SummaryCompleteness, *freshness.Sampling, *freshness.Diagnostics, error) {
|
|
if s.db == nil {
|
|
return nil, nil, nil, nil, nil
|
|
}
|
|
now := time.Now().UTC()
|
|
snapshot, completeness, sampling, diagnostics, err := freshness.BuildSnapshot(
|
|
ctx,
|
|
s.chainID,
|
|
s.db.QueryRow,
|
|
func(ctx context.Context) (*freshness.Reference, error) {
|
|
return freshness.ProbeChainHead(ctx, rpcURL)
|
|
},
|
|
now,
|
|
nil,
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
return nil, nil, nil, nil, err
|
|
}
|
|
return &snapshot, &completeness, &sampling, &diagnostics, nil
|
|
})
|
|
|
|
// Track 1 routes (public, optional auth)
|
|
mux.HandleFunc("/api/v1/track1/blocks/latest", track1Server.HandleLatestBlocks)
|
|
mux.HandleFunc("/api/v1/track1/txs/latest", track1Server.HandleLatestTransactions)
|
|
mux.HandleFunc("/api/v1/track1/block/", track1Server.HandleBlockDetail)
|
|
mux.HandleFunc("/api/v1/track1/tx/", track1Server.HandleTransactionDetail)
|
|
mux.HandleFunc("/api/v1/track1/address/", track1Server.HandleAddressBalance)
|
|
mux.HandleFunc("/api/v1/track1/bridge/status", track1Server.HandleBridgeStatus)
|
|
mux.HandleFunc("/api/v1/mission-control/stream", track1Server.HandleMissionControlStream)
|
|
mux.HandleFunc("/api/v1/mission-control/liquidity/token/", s.handleMissionControlLiquidityTokenPath)
|
|
mux.HandleFunc("/api/v1/mission-control/bridge/trace", s.HandleMissionControlBridgeTrace)
|
|
|
|
// Initialize Track 2 server
|
|
track2Server := track2.NewServer(s.db, s.chainID)
|
|
|
|
// Track 2 routes (require Track 2+)
|
|
track2Middleware := authMiddleware.RequireTrack(2)
|
|
|
|
// Track 2 route handlers with auth
|
|
track2AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
|
|
return authMiddleware.RequireAuth(track2Middleware(http.HandlerFunc(handler))).ServeHTTP
|
|
}
|
|
|
|
mux.HandleFunc("/api/v1/track2/search", track2AuthHandler(track2Server.HandleSearch))
|
|
|
|
// Address routes - need to parse path
|
|
mux.HandleFunc("/api/v1/track2/address/", track2AuthHandler(func(w http.ResponseWriter, r *http.Request) {
|
|
path := r.URL.Path
|
|
parts := strings.Split(strings.TrimPrefix(path, "/api/v1/track2/address/"), "/")
|
|
if len(parts) >= 2 {
|
|
if parts[1] == "txs" {
|
|
track2Server.HandleAddressTransactions(w, r)
|
|
return
|
|
} else if parts[1] == "tokens" {
|
|
track2Server.HandleAddressTokens(w, r)
|
|
return
|
|
} else if parts[1] == "internal-txs" {
|
|
track2Server.HandleInternalTransactions(w, r)
|
|
return
|
|
}
|
|
}
|
|
|
|
writeError(w, http.StatusBadRequest, "bad_request", "Invalid Track 2 address path")
|
|
}))
|
|
|
|
mux.HandleFunc("/api/v1/track2/token/", track2AuthHandler(track2Server.HandleTokenInfo))
|
|
|
|
// Initialize Track 3 server
|
|
track3Server := track3.NewServer(s.db, s.chainID)
|
|
|
|
// Track 3 routes (require Track 3+)
|
|
track3Middleware := authMiddleware.RequireTrack(3)
|
|
track3AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
|
|
return authMiddleware.RequireAuth(track3Middleware(http.HandlerFunc(handler))).ServeHTTP
|
|
}
|
|
|
|
mux.HandleFunc("/api/v1/track3/analytics/flows", track3AuthHandler(track3Server.HandleFlows))
|
|
mux.HandleFunc("/api/v1/track3/analytics/bridge", track3AuthHandler(track3Server.HandleBridge))
|
|
mux.HandleFunc("/api/v1/track3/analytics/token-distribution/", track3AuthHandler(track3Server.HandleTokenDistribution))
|
|
mux.HandleFunc("/api/v1/track3/analytics/address-risk/", track3AuthHandler(track3Server.HandleAddressRisk))
|
|
|
|
// Initialize Track 4 server
|
|
track4Server := track4.NewServer(s.db, s.chainID)
|
|
|
|
// Track 4 routes (require Track 4 + IP whitelist)
|
|
track4Middleware := authMiddleware.RequireTrack(4)
|
|
track4AuthHandler := func(handler http.HandlerFunc) http.HandlerFunc {
|
|
return authMiddleware.RequireAuth(track4Middleware(http.HandlerFunc(handler))).ServeHTTP
|
|
}
|
|
|
|
mux.HandleFunc("/api/v1/track4/operator/bridge/events", track4AuthHandler(track4Server.HandleBridgeEvents))
|
|
mux.HandleFunc("/api/v1/track4/operator/validators", track4AuthHandler(track4Server.HandleValidators))
|
|
mux.HandleFunc("/api/v1/track4/operator/contracts", track4AuthHandler(track4Server.HandleContracts))
|
|
mux.HandleFunc("/api/v1/track4/operator/protocol-state", track4AuthHandler(track4Server.HandleProtocolState))
|
|
mux.HandleFunc("/api/v1/track4/operator/run-script", track4AuthHandler(track4Server.HandleRunScript))
|
|
}
|