@@ -3,7 +3,7 @@ module Echidna.UI.Report where
33import Control.Monad (forM )
44import Control.Monad.Reader (MonadReader , MonadIO (liftIO ), asks , ask )
55import Control.Monad.ST (RealWorld )
6- import Data.IORef (readIORef )
6+ import Data.IORef (readIORef , atomicModifyIORef' )
77import Data.List (intercalate , nub , sortOn )
88import Data.Map (toList )
99import Data.Map qualified as Map
@@ -15,7 +15,8 @@ import Optics
1515
1616import Echidna.ABI (GenDict (.. ), encodeSig )
1717import Echidna.Pretty (ppTxCall )
18- import Echidna.SourceMapping (findSrcByMetadata )
18+ import Echidna.SourceMapping (findSrcByMetadata , lookupCodehash )
19+ import Echidna.Symbolic (forceWord )
1920import Echidna.Types (Gas )
2021import Echidna.Types.Campaign
2122import Echidna.Types.Config
@@ -27,17 +28,17 @@ import Echidna.Utility (timePrefix)
2728
2829import EVM.Format (showTraceTree , contractNamePart )
2930import EVM.Solidity (SolcContract (.. ))
30- import EVM.Types (W256 , VM (labels ), VMType (Concrete ), Addr , Expr (LitAddr ))
31+ import EVM.Types (W256 , VM (labels ), VMType (Concrete ), Addr , Expr (LitAddr ), Contract ( .. ) )
3132
32- ppLogLine :: MonadReader Env m => VM Concrete RealWorld -> (LocalTime , CampaignEvent ) -> m String
33+ ppLogLine :: ( MonadReader Env m , MonadIO m ) => VM Concrete RealWorld -> (LocalTime , CampaignEvent ) -> m String
3334ppLogLine vm (time, event@ (WorkerEvent workerId FuzzWorker _)) =
3435 ((timePrefix time <> " [Worker " <> show workerId <> " ] " ) <> ) <$> ppCampaignEventLog vm event
3536ppLogLine vm (time, event@ (WorkerEvent workerId SymbolicWorker _)) =
3637 ((timePrefix time <> " [Worker " <> show workerId <> " , symbolic] " ) <> ) <$> ppCampaignEventLog vm event
3738ppLogLine vm (time, event) =
3839 ((timePrefix time <> " " ) <> ) <$> ppCampaignEventLog vm event
3940
40- ppCampaignEventLog :: MonadReader Env m => VM Concrete RealWorld -> CampaignEvent -> m String
41+ ppCampaignEventLog :: ( MonadReader Env m , MonadIO m ) => VM Concrete RealWorld -> CampaignEvent -> m String
4142ppCampaignEventLog vm ev = (ppCampaignEvent ev <> ) <$> ppTxIfHas where
4243 ppTxIfHas = case ev of
4344 (WorkerEvent _ _ (TestFalsified test)) -> (" \n Call sequence:\n " <> ) . unlines <$> mapM (ppTx vm $ length (nub $ (. src) <$> test. reproducer) /= 1 ) test. reproducer
@@ -68,7 +69,7 @@ ppCampaign vm workerStates = do
6869
6970-- | Given rules for pretty-printing associated addresses, and whether to print
7071-- them, pretty-print a 'Transaction'.
71- ppTx :: MonadReader Env m => VM Concrete RealWorld -> Bool -> Tx -> m String
72+ ppTx :: ( MonadReader Env m , MonadIO m ) => VM Concrete RealWorld -> Bool -> Tx -> m String
7273ppTx _ _ Tx { call = NoCall , delay } =
7374 pure $ " *wait*" <> ppDelay delay
7475ppTx vm printName tx = do
@@ -92,16 +93,30 @@ ppTx vm printName tx = do
9293 Nothing -> " "
9394 Just l -> " «" <> T. unpack l <> " »"
9495
95- contractNameForAddr :: MonadReader Env m => VM Concrete RealWorld -> Addr -> m Text
96+ contractNameForAddr :: ( MonadReader Env m , MonadIO m ) => VM Concrete RealWorld -> Addr -> m Text
9697contractNameForAddr vm addr = do
97- dapp <- asks (. dapp)
98- maybeName <- case Map. lookup (LitAddr addr) (vm ^. # env % # contracts) of
99- Just contract ->
100- case findSrcByMetadata contract dapp of
101- Just solcContract -> pure $ Just $ contractNamePart solcContract. contractName
102- Nothing -> pure Nothing
103- Nothing -> pure Nothing
104- pure $ fromMaybe (T. pack $ show addr) maybeName
98+ case Map. lookup (LitAddr addr) (vm ^. # env % # contracts) of
99+ Just contract -> do
100+ -- Figure out contract compile-time codehash
101+ codehashMap <- asks (. codehashMap)
102+ dapp <- asks (. dapp)
103+ let codehash = forceWord contract. codehash
104+ compileTimeCodehash <- liftIO $ lookupCodehash codehashMap codehash contract dapp
105+ -- See if we know the name
106+ cache <- asks (. contractNameCache)
107+ nameMap <- liftIO $ readIORef cache
108+ case Map. lookup compileTimeCodehash nameMap of
109+ Just name -> pure name
110+ Nothing -> do
111+ -- Cache miss, compute and store the name
112+ let maybeName = case findSrcByMetadata contract dapp of
113+ Just solcContract -> Just $ contractNamePart solcContract. contractName
114+ Nothing -> Nothing
115+ finalName = fromMaybe (T. pack $ show addr) maybeName
116+ -- Store in cache using compile-time codehash as key
117+ liftIO $ atomicModifyIORef' cache $ \ m -> (Map. insert compileTimeCodehash finalName m, () )
118+ pure finalName
119+ Nothing -> pure $ T. pack $ show addr
105120
106121ppDelay :: (W256 , W256 ) -> [Char ]
107122ppDelay (time, block) =
@@ -123,14 +138,14 @@ ppCorpus = do
123138 pure $ " Corpus size: " <> show (corpusSize corpus)
124139
125140-- | Pretty-print the gas usage information a 'Campaign' has obtained.
126- ppGasInfo :: MonadReader Env m => VM Concrete RealWorld -> [WorkerState ] -> m String
141+ ppGasInfo :: ( MonadReader Env m , MonadIO m ) => VM Concrete RealWorld -> [WorkerState ] -> m String
127142ppGasInfo vm workerStates = do
128143 let gasInfo = Map. unionsWith max ((. gasInfo) <$> workerStates)
129144 items <- mapM (ppGasOne vm) $ sortOn (\ (_, (n, _)) -> n) $ toList gasInfo
130145 pure $ intercalate " " items
131146
132147-- | Pretty-print the gas usage for a function.
133- ppGasOne :: MonadReader Env m => VM Concrete RealWorld -> (Text , (Gas , [Tx ])) -> m String
148+ ppGasOne :: ( MonadReader Env m , MonadIO m ) => VM Concrete RealWorld -> (Text , (Gas , [Tx ])) -> m String
134149ppGasOne _ (" " , _) = pure " "
135150ppGasOne vm (func, (gas, txs)) = do
136151 let header = " \n " <> unpack func <> " used a maximum of " <> show gas <> " gas\n "
@@ -139,7 +154,7 @@ ppGasOne vm (func, (gas, txs)) = do
139154 pure $ header <> unlines ((" " <> ) <$> prettyTxs)
140155
141156-- | Pretty-print the status of a solved test.
142- ppFail :: MonadReader Env m => Maybe (Int , Int ) -> VM Concrete RealWorld -> [Tx ] -> m String
157+ ppFail :: ( MonadReader Env m , MonadIO m ) => Maybe (Int , Int ) -> VM Concrete RealWorld -> [Tx ] -> m String
143158ppFail _ _ [] = pure " failed with no transactions made ⁉️ "
144159ppFail b vm xs = do
145160 let status = case b of
@@ -152,7 +167,7 @@ ppFail b vm xs = do
152167 <> " Traces: \n " <> T. unpack (showTraceTree dappInfo vm)
153168
154169-- | Pretty-print the status of a solved test.
155- ppFailWithTraces :: MonadReader Env m => Maybe (Int , Int ) -> VM Concrete RealWorld -> [(Tx , VM Concrete RealWorld )] -> m String
170+ ppFailWithTraces :: ( MonadReader Env m , MonadIO m ) => Maybe (Int , Int ) -> VM Concrete RealWorld -> [(Tx , VM Concrete RealWorld )] -> m String
156171ppFailWithTraces _ _ [] = pure " failed with no transactions made ⁉️ "
157172ppFailWithTraces b finalVM results = do
158173 dappInfo <- asks (. dapp)
@@ -170,7 +185,7 @@ ppFailWithTraces b finalVM results = do
170185
171186-- | Pretty-print the status of a test.
172187
173- ppTS :: MonadReader Env m => TestState -> VM Concrete RealWorld -> [Tx ] -> m String
188+ ppTS :: ( MonadReader Env m , MonadIO m ) => TestState -> VM Concrete RealWorld -> [Tx ] -> m String
174189ppTS (Failed e) _ _ = pure $ " could not evaluate ☣\n " <> show e
175190ppTS Solved vm l = ppFail Nothing vm l
176191ppTS Passed _ _ = pure " passed! 🎉"
@@ -180,7 +195,7 @@ ppTS (Large n) vm l = do
180195 m <- asks (. cfg. campaignConf. shrinkLimit)
181196 ppFail (if n < m then Just (n, m) else Nothing ) vm l
182197
183- ppOPT :: MonadReader Env m => TestState -> VM Concrete RealWorld -> [Tx ] -> m String
198+ ppOPT :: ( MonadReader Env m , MonadIO m ) => TestState -> VM Concrete RealWorld -> [Tx ] -> m String
184199ppOPT (Failed e) _ _ = pure $ " could not evaluate ☣\n " <> show e
185200ppOPT Solved vm l = ppOptimized Nothing vm l
186201ppOPT Passed _ _ = pure " passed! 🎉"
@@ -190,7 +205,7 @@ ppOPT (Large n) vm l = do
190205 ppOptimized (if n < m then Just (n, m) else Nothing ) vm l
191206
192207-- | Pretty-print the status of an optimized test.
193- ppOptimized :: MonadReader Env m => Maybe (Int , Int ) -> VM Concrete RealWorld -> [Tx ] -> m String
208+ ppOptimized :: ( MonadReader Env m , MonadIO m ) => Maybe (Int , Int ) -> VM Concrete RealWorld -> [Tx ] -> m String
194209ppOptimized _ _ [] = pure " Call sequence:\n (no transactions)"
195210ppOptimized b vm xs = do
196211 let status = case b of
@@ -203,7 +218,7 @@ ppOptimized b vm xs = do
203218 <> " Traces: \n " <> T. unpack (showTraceTree dappInfo vm)
204219
205220-- | Pretty-print the status of all 'SolTest's in a 'Campaign'.
206- ppTests :: MonadReader Env m => [EchidnaTest ] -> m String
221+ ppTests :: ( MonadReader Env m , MonadIO m ) => [EchidnaTest ] -> m String
207222ppTests tests = do
208223 unlines . catMaybes <$> mapM pp tests
209224 where
0 commit comments