44{-# LANGUAGE ExistentialQuantification #-}
55{-# LANGUAGE FlexibleContexts #-}
66{-# LANGUAGE ImportQualifiedPost #-}
7+ {-# LANGUAGE LambdaCase #-}
78{-# LANGUAGE NumericUnderscores #-}
89{-# LANGUAGE OverloadedStrings #-}
910{-# LANGUAGE RankNTypes #-}
@@ -26,65 +27,57 @@ module Chainweb.Mempool.InMem
2627 , txTTLCheck
2728 ) where
2829
29- ------------------------------------------------------------------------------
30+ #if MIN_VERSION_base(4,20,0)
31+ import Data.Foldable (foldlM )
32+ #else
33+ import Data.Foldable (foldl' , foldlM )
34+ #endif
3035
31- import Data.List qualified as List
36+ import Chainweb.BlockHash
37+ import Chainweb.BlockHeight
38+ import Chainweb.Logger
39+ import Chainweb.Mempool.CurrentTxs
40+ import Chainweb.Mempool.InMemTypes
41+ import Chainweb.Mempool.Mempool
42+ import Chainweb.Pact4.Validations (defaultMaxTTL , defaultMaxCoinDecimalPlaces )
43+ import Chainweb.Time
44+ import Chainweb.Utils
45+ import Chainweb.Version (ChainwebVersion )
3246import Control.Applicative ((<|>) )
3347import Control.Concurrent.Async
3448import Control.Concurrent.MVar
3549import Control.DeepSeq
3650import Control.Error.Util (hush )
3751import Control.Exception (evaluate , mask_ , throw )
52+ import Control.Lens
3853import Control.Monad
39-
40- import qualified Data.ByteString.Short as SB
54+ import Control.Monad.IO.Class (liftIO )
55+ import Control.Monad.Except (runExceptT , throwError )
56+ import Data.ByteString (ByteString )
57+ import Data.ByteString qualified as BS
58+ import Data.ByteString.Short qualified as SB
4159import Data.Decimal
42- #if MIN_VERSION_base(4,20,0)
43- import Data.Foldable (foldlM )
44- #else
45- import Data.Foldable (foldl' , foldlM )
46- #endif
60+ import Data.Either (partitionEithers )
4761import Data.Function (on )
4862import Data.HashMap.Strict (HashMap )
49- import qualified Data.HashMap.Strict as HashMap
63+ import Data.HashMap.Strict qualified as HashMap
5064import Data.IORef (modifyIORef' , newIORef , readIORef , writeIORef )
65+ import Data.List qualified as List
5166import Data.Maybe
5267import Data.Ord
53- import qualified Data.Set as S
54- import qualified Data.Text as T
55- import qualified Data.Text.Encoding as T
56- import Data.Traversable (for )
68+ import Data.Set qualified as S
69+ import Data.Text qualified as T
70+ import Data.Text.Encoding qualified as T
5771import Data.Vector (Vector )
58- import qualified Data.Vector as V
59- import qualified Data.Vector.Algorithms.Tim as TimSort
60-
72+ import Data.Vector qualified as V
73+ import Data.Vector.Algorithms.Tim qualified as TimSort
74+ import Numeric.AffineSpace
6175import Pact.Parse
62-
76+ import Pact.Types.ChainMeta qualified as P
6377import Prelude hiding (init , lookup , pred )
64-
6578import System.LogLevel
6679import System.Random
6780
68- -- internal imports
69-
70- import Chainweb.BlockHash
71- import Chainweb.BlockHeight
72- import Chainweb.Logger
73- import Chainweb.Mempool.CurrentTxs
74- import Chainweb.Mempool.InMemTypes
75- import Chainweb.Mempool.Mempool
76- import Chainweb.Pact4.Validations (defaultMaxTTL , defaultMaxCoinDecimalPlaces )
77- import Chainweb.Time
78- import Chainweb.Utils
79- import Chainweb.Version (ChainwebVersion )
80-
81- import qualified Pact.Types.ChainMeta as P
82-
83- import Numeric.AffineSpace
84- import Data.ByteString (ByteString )
85- import Data.Either (partitionEithers )
86- import Control.Lens
87-
8881------------------------------------------------------------------------------
8982compareOnGasPrice :: TransactionConfig t -> t -> t -> Ordering
9083compareOnGasPrice txcfg a b = compare aa bb
@@ -102,16 +95,15 @@ makeInMemPool cfg = mask_ $ do
10295 dataLock <- newInMemMempoolData >>= newMVar
10396 return $! InMemoryMempool cfg dataLock nonce
10497
105-
10698------------------------------------------------------------------------------
99+
107100newInMemMempoolData :: IO (InMemoryMempoolData t )
108101newInMemMempoolData =
109102 InMemoryMempoolData <$!> newIORef mempty
110103 <*> newIORef emptyRecentLog
111104 <*> newIORef mempty
112105 <*> newIORef newCurrentTxs
113106
114-
115107------------------------------------------------------------------------------
116108toMempoolBackend
117109 :: forall t logger
@@ -127,8 +119,8 @@ toMempoolBackend logger mempool = do
127119 , mempoolLookup = lookupInMem tcfg lockMVar
128120 , mempoolLookupEncoded = lookupEncodedInMem lockMVar
129121 , mempoolInsert = insertInMem logger cfg lockMVar
130- , mempoolInsertCheck = insertCheckInMem cfg lockMVar
131- , mempoolInsertCheckVerbose = insertCheckVerboseInMem cfg lockMVar
122+ , mempoolInsertCheck = insertCheckInMem logger cfg lockMVar
123+ , mempoolInsertCheckVerbose = insertCheckVerboseInMem logger cfg lockMVar
132124 , mempoolMarkValidated = markValidatedInMem logger tcfg lockMVar
133125 , mempoolAddToBadList = addToBadListInMem lockMVar
134126 , mempoolCheckBadList = checkBadListInMem lockMVar
@@ -306,13 +298,13 @@ maxNumPending = 10000
306298-- the latter case.
307299--
308300insertCheckInMem
309- :: forall t
310- . NFData t
311- = > InMemConfig t -- ^ in-memory config
301+ :: forall logger t . ( NFData t , Logger logger )
302+ => logger
303+ - > InMemConfig t -- ^ in-memory config
312304 -> MVar (InMemoryMempoolData t ) -- ^ in-memory state
313305 -> Vector t -- ^ new transactions
314306 -> IO (Either (T2 TransactionHash InsertError ) () )
315- insertCheckInMem cfg lock txs
307+ insertCheckInMem logger cfg lock txs
316308 | V. null txs = pure $ Right ()
317309 | otherwise = do
318310 now <- getCurrentTimeIntegral
@@ -321,10 +313,14 @@ insertCheckInMem cfg lock txs
321313
322314 -- We hash the tx here and pass it around around to avoid needing to repeat
323315 -- the hashing effort.
324- let withHashes :: Either (T2 TransactionHash InsertError ) (Vector (T2 TransactionHash t ))
325- withHashes = for txs $ \ tx ->
326- let ! h = hasher tx
327- in bimap (T2 h) (T2 h) $ validateOne cfg badmap curTxIdx now tx h
316+ withHashes :: Either (T2 TransactionHash InsertError ) (Vector (T2 TransactionHash t )) <- runExceptT $ do
317+ forM txs $ \ tx -> do
318+ let ! h = hasher tx
319+ case validateOne cfg badmap curTxIdx now tx h of
320+ Right t -> pure (T2 h t)
321+ Left insertErr -> do
322+ liftIO $ logValidateOneFailure logger " insertCheckInMem" h insertErr
323+ throwError (T2 h insertErr)
328324
329325 case withHashes of
330326 Left _ -> pure $! void withHashes
@@ -340,27 +336,33 @@ insertCheckInMem cfg lock txs
340336-- and the creation time of the parent header in the latter case (new block creation).
341337--
342338insertCheckVerboseInMem
343- :: forall t
344- . NFData t
345- = > InMemConfig t -- ^ in-memory config
339+ :: forall t logger . ( NFData t , Logger logger )
340+ => logger
341+ - > InMemConfig t -- ^ in-memory config
346342 -> MVar (InMemoryMempoolData t ) -- ^ in-memory state
347343 -> Vector t -- ^ new transactions
348344 -> IO (Vector (T2 TransactionHash (Either InsertError t )))
349- insertCheckVerboseInMem cfg lock txs
345+ insertCheckVerboseInMem logger cfg lock txs
350346 | V. null txs = return V. empty
351347 | otherwise = do
352348 now <- getCurrentTimeIntegral
353349 badmap <- withMVarMasked lock $ readIORef . _inmemBadMap
354350 curTxIdx <- withMVarMasked lock $ readIORef . _inmemCurrentTxs
355-
356- let withHashesAndPositions :: (HashMap TransactionHash (Int , InsertError ), HashMap TransactionHash (Int , t ))
357- withHashesAndPositions =
358- over _1 (HashMap. fromList . V. toList)
359- $ over _2 (HashMap. fromList . V. toList)
360- $ V. partitionWith (\ (i, h, e) -> bimap (\ err -> (h, (i, err))) (\ err -> (h, (i, err))) e)
361- $ flip V. imap txs $ \ i tx ->
362- let ! h = hasher tx
363- in (i, h,) $! validateOne cfg badmap curTxIdx now tx h
351+
352+ withHashesAndPositions :: (HashMap TransactionHash (Int , InsertError ), HashMap TransactionHash (Int , t )) <- do
353+ pos <- flip V. imapM txs $ \ i tx -> do
354+ let ! h = hasher tx
355+ case validateOne cfg badmap curTxIdx now tx h of
356+ Right t -> pure (i, h, Right t)
357+ Left insertErr -> do
358+ logValidateOneFailure logger " insertCheckVerboseInMem" h insertErr
359+ pure (i, h, Left insertErr)
360+
361+ pure
362+ $ over _1 (HashMap. fromList . V. toList)
363+ $ over _2 (HashMap. fromList . V. toList)
364+ $ V. partitionWith (\ (i, h, e) -> bimap (\ err -> (h, (i, err))) (\ err -> (h, (i, err))) e)
365+ $ pos
364366
365367 let (prevFailures, prevSuccesses) = withHashesAndPositions
366368
@@ -496,23 +498,27 @@ txTTLCheck txcfg now t = do
496498-- the latter case.
497499--
498500insertCheckInMem'
499- :: forall t
500- . NFData t
501- = > InMemConfig t -- ^ in-memory config
501+ :: forall t logger . ( NFData t , Logger logger )
502+ => logger
503+ - > InMemConfig t -- ^ in-memory config
502504 -> MVar (InMemoryMempoolData t ) -- ^ in-memory state
503505 -> Vector t -- ^ new transactions
504506 -> IO (Vector (T2 TransactionHash t ))
505- insertCheckInMem' cfg lock txs
507+ insertCheckInMem' logger cfg lock txs
506508 | V. null txs = pure V. empty
507509 | otherwise = do
508510 now <- getCurrentTimeIntegral
509511 badmap <- withMVarMasked lock $ readIORef . _inmemBadMap
510512 curTxIdx <- withMVarMasked lock $ readIORef . _inmemCurrentTxs
511513
512- let withHashes :: Vector (T2 TransactionHash t )
513- withHashes = flip V. mapMaybe txs $ \ tx ->
514- let ! h = hasher tx
515- in (T2 h) <$> hush (validateOne cfg badmap curTxIdx now tx h)
514+ withHashes :: Vector (T2 TransactionHash t ) <- do
515+ flip V. mapMaybeM txs $ \ tx -> do
516+ let ! h = hasher tx
517+ case validateOne cfg badmap curTxIdx now tx h of
518+ Right t -> pure (Just (T2 h t))
519+ Left insertErr -> do
520+ logValidateOneFailure logger " insertCheckInMem'" h insertErr
521+ pure Nothing
516522
517523 V. mapMaybe hush <$!> _inmemPreInsertBatchChecks cfg withHashes
518524 where
@@ -544,7 +550,7 @@ insertInMem logger cfg lock runCheck txs0 = do
544550 where
545551 insertCheck :: IO (Vector (T2 TransactionHash t ))
546552 insertCheck = case runCheck of
547- CheckedInsert -> insertCheckInMem' cfg lock txs0
553+ CheckedInsert -> insertCheckInMem' logger cfg lock txs0
548554 UncheckedInsert -> return $! V. map (\ tx -> T2 (hasher tx) tx) txs0
549555
550556 txcfg = _inmemTxCfg cfg
@@ -867,3 +873,13 @@ pruneInternal logger mdata now = do
867873 -- keep transactions that expire in the future.
868874 flt pe = _inmemPeExpires pe > now
869875 pruneBadMap = HashMap. filter (> now)
876+
877+ logValidateOneFailure :: (Logger logger )
878+ => logger
879+ -> T. Text -- ^ location
880+ -> TransactionHash
881+ -> InsertError
882+ -> IO ()
883+ logValidateOneFailure logger loc (TransactionHash hsb) insertErr = do
884+ let abbrevReqKey = T. decodeUtf8 (BS. take 6 (SB. fromShort hsb))
885+ logFunctionText logger Info $ loc <> " : " <> abbrevReqKey <> " ... failed mempool check. " <> sshow insertErr
0 commit comments