From 43ff96b7a85d6c928bf9b24ab6d1e1c4cf0ba032 Mon Sep 17 00:00:00 2001 From: Trajan0x Date: Fri, 3 May 2024 20:23:11 +0200 Subject: [PATCH 1/3] cache api result [goreleaser] --- services/rfq/api/rest/server.go | 54 +++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index 76dd5b4eb3..93d74511e0 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/gin-gonic/gin" + "github.com/jellydator/ttlcache/v3" "github.com/synapsecns/sanguine/core/metrics" baseServer "github.com/synapsecns/sanguine/core/server" omniClient "github.com/synapsecns/sanguine/services/omnirpc/client" @@ -35,6 +36,7 @@ type QuoterAPIServer struct { omnirpcClient omniClient.RPCClient handler metrics.Handler fastBridgeContracts map[uint32]*fastbridge.FastBridge + roleCache map[uint32]*ttlcache.Cache[string, bool] } // NewAPI holds the configuration, database connection, gin engine, RPC client, metrics handler, and fast bridge contracts. @@ -62,6 +64,7 @@ func NewAPI( docs.SwaggerInfo.Title = "RFQ Quoter API" bridges := make(map[uint32]*fastbridge.FastBridge) + roles := make(map[uint32]*ttlcache.Cache[string, bool]) for chainID, bridge := range cfg.Bridges { chainClient, err := omniRPCClient.GetChainClient(ctx, int(chainID)) if err != nil { @@ -71,6 +74,27 @@ func NewAPI( if err != nil { return nil, fmt.Errorf("could not create bridge contract: %w", err) } + + // create the roles cache + roles[chainID] = ttlcache.New[string, bool]( + ttlcache.WithTTL[string, bool](cacheInterval), + ) + // purge periodically + const cachePurgeInterval = 5 * time.Second + cacheTimer := time.NewTimer(cachePurgeInterval) + + roleCache := roles[chainID] + + go func() { + select { + case <-ctx.Done(): + cacheTimer.Stop() + case <-cacheTimer.C: + cacheTimer.Reset(cachePurgeInterval) + roleCache.DeleteExpired() + } + }() + } return &QuoterAPIServer{ @@ -79,12 +103,14 @@ func NewAPI( omnirpcClient: omniRPCClient, handler: handler, fastBridgeContracts: bridges, + roleCache: roles, }, nil } // QuoteRoute is the API endpoint for handling quote related requests. const ( - QuoteRoute = "/quotes" + QuoteRoute = "/quotes" + cacheInterval = time.Minute ) var logger = log.Logger("rfq-api") @@ -145,15 +171,23 @@ func (r *QuoterAPIServer) AuthMiddleware() gin.HandlerFunc { return } - has, err := bridge.HasRole(ops, relayerRole, addressRecovered) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"msg": "unable to check relayer role on-chain"}) - c.Abort() - return - } else if !has { - c.JSON(http.StatusBadRequest, gin.H{"msg": "q.Relayer not an on-chain relayer"}) - c.Abort() - return + hasRole := r.roleCache[uint32(req.DestChainID)].Get(addressRecovered.Hex()) + + if hasRole == nil || hasRole.IsExpired() { + has, err := bridge.HasRole(ops, relayerRole, addressRecovered) + if err == nil { + r.roleCache[uint32(req.DestChainID)].Set(addressRecovered.Hex(), has, cacheInterval) + } + + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"msg": "unable to check relayer role on-chain"}) + c.Abort() + return + } else if !has { + c.JSON(http.StatusBadRequest, gin.H{"msg": "q.Relayer not an on-chain relayer"}) + c.Abort() + return + } } // Log and pass to the next middleware if authentication succeeds From b55569907d1f2486ee1434b53eea0b708b3501a7 Mon Sep 17 00:00:00 2001 From: Trajan0x Date: Sat, 4 May 2024 18:35:29 +0200 Subject: [PATCH 2/3] clean up --- services/rfq/api/rest/server.go | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index 93d74511e0..f17463aada 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -79,24 +79,18 @@ func NewAPI( roles[chainID] = ttlcache.New[string, bool]( ttlcache.WithTTL[string, bool](cacheInterval), ) - // purge periodically - const cachePurgeInterval = 5 * time.Second - cacheTimer := time.NewTimer(cachePurgeInterval) - roleCache := roles[chainID] - go func() { - select { - case <-ctx.Done(): - cacheTimer.Stop() - case <-cacheTimer.C: - cacheTimer.Reset(cachePurgeInterval) - roleCache.DeleteExpired() - } - }() - + roleCache.Start() } + go func() { + <-ctx.Done() + for _, roleCache := range roles { + roleCache.Stop() + } + }() + return &QuoterAPIServer{ cfg: cfg, db: store, From 942d68377687957d1cbfe9a1bfc697b6b14cb0da Mon Sep 17 00:00:00 2001 From: Trajan0x Date: Sat, 4 May 2024 18:35:45 +0200 Subject: [PATCH 3/3] clean up 2 --- services/rfq/api/rest/server.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/services/rfq/api/rest/server.go b/services/rfq/api/rest/server.go index f17463aada..03e2693edc 100644 --- a/services/rfq/api/rest/server.go +++ b/services/rfq/api/rest/server.go @@ -82,14 +82,11 @@ func NewAPI( roleCache := roles[chainID] roleCache.Start() - } - - go func() { - <-ctx.Done() - for _, roleCache := range roles { + go func() { + <-ctx.Done() roleCache.Stop() - } - }() + }() + } return &QuoterAPIServer{ cfg: cfg,