Skip to content

Commit 9df353f

Browse files
better handling of parsing injected transactions
1 parent b521a45 commit 9df353f

File tree

2 files changed

+47
-9
lines changed

2 files changed

+47
-9
lines changed

lib/Echidna/Agent/Fuzzer.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ randseq deployedContracts = do
233233
seqLen = env.cfg.campaignConf.seqLen
234234

235235
prioritized <- gets (.prioritizedSequences)
236-
usePrioritized <- (<= (0.25 :: Double)) <$> getRandom
236+
usePrioritized <- (<= (0.90 :: Double)) <$> getRandom
237237

238238
if not (null prioritized) && usePrioritized
239239
then do

lib/Echidna/MCP.hs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,24 @@ import Control.Concurrent (forkIO)
77
import Control.Monad (forever, unless)
88
import Control.Concurrent.STM
99
import Data.IORef (readIORef, modifyIORef', newIORef, IORef, atomicModifyIORef')
10-
import Data.List (find, isPrefixOf, sort, intercalate)
10+
import Data.List (find, isPrefixOf, isSuffixOf, sort, intercalate)
1111
import qualified Data.Maybe
1212
import qualified Data.Set as Set
13+
import qualified Data.Vector as Vector
1314
import Data.Text (Text, pack, unpack)
1415
import qualified Data.Text as T
1516
import Data.Time (UTCTime, getCurrentTime, diffUTCTime)
1617
import Text.Printf (printf)
1718
import qualified Data.Map as Map
1819
import Text.Read (readMaybe)
1920
import System.Directory (getCurrentDirectory)
20-
import Data.Char (isSpace)
21+
import Data.Char (isSpace, toLower)
2122

2223
import MCP.Server
2324
import EVM.Dapp (DappInfo(..))
2425
import EVM.Solidity (SolcContract(..), Method(..))
2526
import EVM.Types (Addr)
26-
import EVM.ABI (AbiValue(..))
27+
import EVM.ABI (AbiValue(..), AbiType(..), abiValueType)
2728
import Echidna.Types.Test (EchidnaTest(..), didFail, isOptimizationTest)
2829
import Echidna.Types.Tx (Tx(..), TxCall(..))
2930
import Echidna.Types.Coverage (CoverageFileType(..), mergeCoverageMaps, coverageStats)
@@ -105,12 +106,49 @@ splitOn c s = case break (== c) s of
105106
[] -> []
106107
(_:r) -> splitOn c r
107108

109+
splitArgs :: String -> [String]
110+
splitArgs s = go s 0 ""
111+
where
112+
go :: String -> Int -> String -> [String]
113+
go [] _ current = [reverse current]
114+
go (c:cs) level current
115+
| c == '[' = go cs (level + 1) (c:current)
116+
| c == ']' = go cs (level - 1) (c:current)
117+
| c == ',' && level == 0 = reverse current : go cs level ""
118+
| otherwise = go cs level (c:current)
119+
120+
parsePrimitive :: String -> Maybe AbiValue
121+
parsePrimitive s =
122+
let s' = trim s
123+
lowerS = map toLower s'
124+
in if lowerS == "true"
125+
then Just (AbiBool True)
126+
else if lowerS == "false"
127+
then Just (AbiBool False)
128+
else if "0x" `isPrefixOf` s'
129+
then AbiAddress . fromIntegral <$> (readMaybe s' :: Maybe Integer)
130+
else AbiUInt 256 . fromIntegral <$> (readMaybe s' :: Maybe Integer)
131+
132+
parseArray :: String -> Maybe AbiValue
133+
parseArray s = do
134+
let content = trim (drop 1 (take (length s - 1) s))
135+
let parts = if null content then [] else splitOn ',' content
136+
vals <- mapM parsePrimitive parts
137+
let vec = Vector.fromList vals
138+
if Vector.null vec
139+
then return $ AbiArrayDynamic (AbiUIntType 256) vec
140+
else do
141+
let t = abiValueType (Vector.head vec)
142+
if all (\v -> abiValueType v == t) vals
143+
then return $ AbiArrayDynamic t vec
144+
else Nothing
145+
108146
parseArg :: String -> Maybe AbiValue
109147
parseArg s =
110148
let s' = trim s
111-
in if "0x" `isPrefixOf` s'
112-
then AbiAddress . fromIntegral <$> (readMaybe s' :: Maybe Integer)
113-
else AbiUInt 256 . fromIntegral <$> (readMaybe s' :: Maybe Integer)
149+
in if "[" `isPrefixOf` s' && "]" `isSuffixOf` s'
150+
then parseArray s'
151+
else parsePrimitive s'
114152

115153
parseFuzzArg :: String -> Maybe (Maybe AbiValue)
116154
parseFuzzArg s =
@@ -124,7 +162,7 @@ parseFuzzCall s = do
124162
let (fname, rest) = break (== '(') s
125163
if null rest then Nothing else do
126164
let argsS = take (length rest - 2) (drop 1 rest) -- remove parens
127-
let argParts = if all isSpace argsS then [] else splitOn ',' argsS
165+
let argParts = if all isSpace argsS then [] else splitArgs argsS
128166
args <- mapM parseFuzzArg argParts
129167
return (pack fname, args)
130168

@@ -136,7 +174,7 @@ parseCall s = do
136174
let (fname, rest) = break (== '(') s
137175
if null rest then Nothing else do
138176
let argsS = take (length rest - 2) (drop 1 rest) -- remove parens
139-
let argParts = if all isSpace argsS then [] else splitOn ',' argsS
177+
let argParts = if all isSpace argsS then [] else splitArgs argsS
140178
args <- mapM parseArg argParts
141179
return (fname, args)
142180

0 commit comments

Comments
 (0)