Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.

Commit 83aa36e

Browse files
committed
wip: new rate limiter
1 parent 80a188b commit 83aa36e

File tree

11 files changed

+518
-146
lines changed

11 files changed

+518
-146
lines changed

chainweb.cabal

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ library
256256
, Chainweb.Utils.RequestLog
257257
, Chainweb.Utils.Rule
258258
, Chainweb.Utils.Serialization
259+
, Chainweb.Utils.Throttle
260+
, Chainweb.Utils.TokenLimiting
259261
, Chainweb.VerifierPlugin
260262
, Chainweb.VerifierPlugin.Allow
261263
, Chainweb.VerifierPlugin.Hyperlane.Announcement
@@ -380,6 +382,7 @@ library
380382
, base64-bytestring-kadena == 0.1
381383
, binary >= 0.8
382384
, bytestring >= 0.10.12
385+
, cache >= 0.1.1.2
383386
, case-insensitive >= 1.2
384387
, cassava >= 0.5.1
385388
, chainweb-storage >= 0.1
@@ -455,7 +458,7 @@ library
455458
, time >= 1.12.2
456459
, tls >=2.1.4
457460
, tls-session-manager >= 0.0
458-
, token-bucket >= 0.1
461+
, token-limiter >= 0.1
459462
, transformers >= 0.5
460463
, trifecta >= 2.1
461464
, unliftio >= 0.2
@@ -665,6 +668,7 @@ test-suite chainweb-tests
665668
Chainweb.Test.SPV
666669
Chainweb.Test.SPV.EventProof
667670
Chainweb.Test.Sync.WebBlockHeaderStore
671+
Chainweb.Test.Throttle
668672
Chainweb.Test.TreeDB
669673
Chainweb.Test.TreeDB.RemoteDB
670674
Chainweb.Test.Version

src/Chainweb/Chainweb.hs

Lines changed: 40 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,6 @@ module Chainweb.Chainweb
6161
, chainwebPeer
6262
, chainwebPayloadDb
6363
, chainwebPactData
64-
, chainwebThrottler
65-
, chainwebPutPeerThrottler
66-
, chainwebMempoolThrottler
6764
, chainwebConfig
6865
, chainwebServiceSocket
6966
, chainwebBackup
@@ -79,15 +76,7 @@ module Chainweb.Chainweb
7976
, runChainweb
8077

8178
-- * Throttler
82-
, mkGenericThrottler
83-
, mkPutPeerThrottler
8479
, checkPathPrefix
85-
, mkThrottler
86-
87-
, ThrottlingConfig(..)
88-
, throttlingRate
89-
, throttlingPeerRate
90-
, defaultThrottlingConfig
9180

9281
-- * Cut Config
9382
, CutConfig(..)
@@ -128,11 +117,9 @@ import Network.Wai
128117
import Network.Wai.Handler.Warp hiding (Port)
129118
import Network.Wai.Handler.WarpTLS (WarpTLSException(..))
130119
import Network.Wai.Middleware.RequestSizeLimit
131-
import Network.Wai.Middleware.Throttle
132120

133121
import Prelude hiding (log)
134122

135-
import System.Clock
136123
import System.LogLevel
137124

138125
-- internal modules
@@ -184,6 +171,7 @@ import P2P.Peer
184171

185172
import qualified Pact.Types.ChainMeta as P
186173
import qualified Pact.Types.Command as P
174+
import qualified Chainweb.Utils.Throttle as Throttle
187175

188176
-- -------------------------------------------------------------------------- --
189177
-- Chainweb Resources
@@ -199,9 +187,6 @@ data Chainweb logger tbl = Chainweb
199187
, _chainwebPayloadDb :: !(PayloadDb tbl)
200188
, _chainwebManager :: !HTTP.Manager
201189
, _chainwebPactData :: ![(ChainId, PactServerData logger tbl)]
202-
, _chainwebThrottler :: !(Throttle Address)
203-
, _chainwebPutPeerThrottler :: !(Throttle Address)
204-
, _chainwebMempoolThrottler :: !(Throttle Address)
205190
, _chainwebConfig :: !ChainwebConfiguration
206191
, _chainwebServiceSocket :: !(Port, Socket)
207192
, _chainwebBackup :: !(BackupEnv logger)
@@ -488,13 +473,6 @@ withChainwebInternal conf logger peer serviceSock rocksDb pactDbDir backupDir re
488473
let !mLogger = setComponent "miner" logger
489474
!mConf = _configMining conf
490475
!mCutDb = _cutResCutDb cuts
491-
!throt = _configThrottling conf
492-
493-
-- initialize throttler
494-
throttler <- mkGenericThrottler $ _throttlingRate throt
495-
putPeerThrottler <- mkPutPeerThrottler $ _throttlingPeerRate throt
496-
mempoolThrottler <- mkMempoolThrottler $ _throttlingMempoolRate throt
497-
logg Debug "initialized throttlers"
498476

499477
-- synchronize pact dbs with latest cut before we start the server
500478
-- and clients and begin mining.
@@ -588,9 +566,6 @@ withChainwebInternal conf logger peer serviceSock rocksDb pactDbDir backupDir re
588566
, _chainwebPayloadDb = view cutDbPayloadDb $ _cutResCutDb cuts
589567
, _chainwebManager = mgr
590568
, _chainwebPactData = pactData
591-
, _chainwebThrottler = throttler
592-
, _chainwebPutPeerThrottler = putPeerThrottler
593-
, _chainwebMempoolThrottler = mempoolThrottler
594569
, _chainwebConfig = conf
595570
, _chainwebServiceSocket = serviceSock
596571
, _chainwebBackup = BackupEnv
@@ -650,41 +625,13 @@ withChainwebInternal conf logger peer serviceSock rocksDb pactDbDir backupDir re
650625
-- -------------------------------------------------------------------------- --
651626
-- Throttling
652627

653-
mkGenericThrottler :: Double -> IO (Throttle Address)
654-
mkGenericThrottler rate = mkThrottler 30 rate (const True)
655-
656-
mkPutPeerThrottler :: Double -> IO (Throttle Address)
657-
mkPutPeerThrottler rate = mkThrottler 30 rate $ \r ->
658-
elem "peer" (pathInfo r) && requestMethod r == "PUT"
659-
660-
mkMempoolThrottler :: Double -> IO (Throttle Address)
661-
mkMempoolThrottler rate = mkThrottler 30 rate $ \r ->
662-
elem "mempool" (pathInfo r)
663-
664628
checkPathPrefix
665629
:: [T.Text]
666630
-- ^ the base rate granted to users of the endpoing
667631
-> Request
668632
-> Bool
669633
checkPathPrefix endpoint r = endpoint `isPrefixOf` drop 3 (pathInfo r)
670634

671-
-- | The period is 1 second. Burst is 2*rate.
672-
--
673-
mkThrottler
674-
:: Double
675-
-- ^ expiration of a stall bucket in seconds
676-
-> Double
677-
-- ^ the base rate granted to users of the endpoint (requests per second)
678-
-> (Request -> Bool)
679-
-- ^ Predicate to select requests that are throttled
680-
-> IO (Throttle Address)
681-
mkThrottler e rate c = initThrottler (defaultThrottleSettings $ TimeSpec (ceiling e) 0) -- expiration
682-
{ throttleSettingsRate = rate -- number of allowed requests per period
683-
, throttleSettingsPeriod = 1_000_000 -- 1 second
684-
, throttleSettingsBurst = 4 * ceiling rate
685-
, throttleSettingsIsThrottled = c
686-
}
687-
688635
-- -------------------------------------------------------------------------- --
689636
-- Run Chainweb
690637

@@ -720,28 +667,40 @@ runChainweb cw nowServing = do
720667
logg Warn $ "OpenAPI spec validation enabled on service API, make sure this is what you want"
721668
mkValidationMiddleware
722669
else return id
723-
724-
concurrentlies_
725-
726-
-- 1. Start serving Rest API
727-
[ (if tls then serve else servePlain)
728-
$ httpLog
729-
. throttle (_chainwebPutPeerThrottler cw)
730-
. throttle (_chainwebMempoolThrottler cw)
731-
. throttle (_chainwebThrottler cw)
732-
. p2pRequestSizeLimit
733-
. p2pValidationMiddleware
734-
735-
-- 2. Start Clients (with a delay of 500ms)
736-
, threadDelay 500000 >> clients
737-
738-
-- 3. Start serving local API
739-
, threadDelay 500000 >> do
740-
serveServiceApi
741-
$ serviceHttpLog
742-
. serviceRequestSizeLimit
743-
. serviceApiValidationMiddleware
744-
]
670+
let theP2pThrottleConfig = cw ^. chainwebConfig . configP2p . p2pConfigThrottleConfig
671+
let theServiceApiThrottleConfig = cw ^. chainwebConfig . configServiceApi . serviceApiConfigThrottleConfig
672+
let withP2pThrottleMiddleware =
673+
if _enableConfigEnabled theP2pThrottleConfig
674+
then Throttle.throttleMiddleware (logFunction $ _chainwebLogger cw) "p2p" (_enableConfigConfig theP2pThrottleConfig)
675+
else \k -> k id
676+
let withServiceApiThrottleMiddleware =
677+
if _enableConfigEnabled theServiceApiThrottleConfig
678+
then Throttle.throttleMiddleware (logFunction $ _chainwebLogger cw) "p2p" (_enableConfigConfig theServiceApiThrottleConfig)
679+
else \k -> k id
680+
681+
withP2pThrottleMiddleware $ \p2pThrottler ->
682+
withServiceApiThrottleMiddleware $ \serviceThrottler ->
683+
684+
concurrentlies_
685+
686+
-- 1. Start serving Rest API
687+
[ (if tls then serve else servePlain)
688+
$ httpLog
689+
. p2pRequestSizeLimit
690+
. p2pThrottler
691+
. p2pValidationMiddleware
692+
693+
-- 2. Start Clients (with a delay of 500ms)
694+
, threadDelay 500000 >> clients
695+
696+
-- 3. Start serving local API
697+
, threadDelay 500000 >> do
698+
serveServiceApi
699+
$ serviceHttpLog
700+
. serviceRequestSizeLimit
701+
. serviceThrottler
702+
. serviceApiValidationMiddleware
703+
]
745704

746705
where
747706

@@ -805,12 +764,16 @@ runChainweb cw nowServing = do
805764
when (defaultShouldDisplayException e) $
806765
logg Debug $ loggServerError msg r e
807766

767+
onExceptionResponse ex =
768+
fromMaybe (defaultOnExceptionResponse ex) (Throttle.throttledResponse ex)
769+
808770
-- P2P Server
809771

810772
serverSettings :: Counter "clientClosedConnections" -> Settings
811773
serverSettings clientClosedConnectionsCounter =
812774
peerServerSettings (_peerResPeer $ _chainwebPeer cw)
813775
& setOnException (logWarpException "P2P API" clientClosedConnectionsCounter)
776+
& setOnExceptionResponse onExceptionResponse
814777
& setBeforeMainLoop (nowServing (nowServingP2PAPI .~ True))
815778

816779
monitorConnectionsClosedByClient :: Counter "clientClosedConnections" -> IO ()
@@ -893,6 +856,7 @@ runChainweb cw nowServing = do
893856
& setHost interface
894857
& setOnException
895858
(logWarpException "Service API" clientClosedConnectionsCounter)
859+
& setOnExceptionResponse onExceptionResponse
896860
& setBeforeMainLoop (nowServing (nowServingServiceAPI .~ True))
897861
& setServerName "Chainweb Service API"
898862

0 commit comments

Comments
 (0)