Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for reaching receive #722

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/Echidna/ABI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ import Echidna.Types.Signature

-- | Fallback function is the null string
fallback :: SolSignature
fallback = ("",[])
fallback = ("*fallback*",[])
Copy link

@Jaime-Iglesias Jaime-Iglesias Feb 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fallback functions can have parameters (i.e calldata), the receive function on the other hand is executed only when calldata is empty, so I'm not sure if this will fix all cases.


receive :: SolSignature
receive = ("*receive*",[])

commonTypeSizes :: [Int]
commonTypeSizes = [8,16..256]
Expand Down
4 changes: 2 additions & 2 deletions lib/Echidna/Solidity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import System.Exit (ExitCode(..))
import System.Directory (doesDirectoryExist, doesFileExist, findExecutable, listDirectory, removeFile)
import System.FilePath.Posix ((</>))

import Echidna.ABI (encodeSig, encodeSigWithName, hashSig, fallback, commonTypeSizes, mkValidAbiInt, mkValidAbiUInt)
import Echidna.ABI (encodeSig, encodeSigWithName, hashSig, fallback, receive, commonTypeSizes, mkValidAbiInt, mkValidAbiUInt)
import Echidna.Exec (execTx, initialVM)
import Echidna.Events (EventMap)
import Echidna.Test (createTests, isAssertionMode, isPropertyMode)
Expand Down Expand Up @@ -144,7 +144,7 @@ filterMethods cn f@(Blacklist ig) ms = case NE.filter (\s -> encodeSigWithName c
fs -> NE.fromList fs

abiOf :: Text -> SolcContract -> NE.NonEmpty SolSignature
abiOf pref cc = fallback NE.:| filter (not . isPrefixOf pref . fst) (elems (cc ^. abiMap) <&> \m -> (m ^. methodName, m ^.. methodInputs . traverse . _2))
abiOf pref cc = fallback NE.<| (receive NE.:| filter (not . isPrefixOf pref . fst) (elems (cc ^. abiMap) <&> \m -> (m ^. methodName, m ^.. methodInputs . traverse . _2)))

-- | Given an optional contract name and a list of 'SolcContract's, try to load the specified
-- contract, or, if not provided, the first contract in the list, into a 'VM' usable for Echidna
Expand Down
10 changes: 6 additions & 4 deletions lib/Echidna/Transaction.hs
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,12 @@ setupTx (Tx c s r g gp v (t, b)) = liftSH . sequence_ $
, tx . gasprice .= gp, tx . origin .= s, state . caller .= litAddr s, state . callvalue .= litWord v
, block . timestamp += litWord t, block . number += b, setup] where
setup = case c of
SolCreate bc -> assign (env . contracts . at r) (Just $ initialContract (InitCode (ConcreteBuffer bc)) & set balance v) >> loadContract r >> state . code .= ConcreteBuffer bc
SolCall cd -> incrementBalance >> loadContract r >> state . calldata .= concreteCalldata (encode cd)
SolCalldata cd -> incrementBalance >> loadContract r >> state . calldata .= concreteCalldata cd
NoCall -> error "NoCall"
SolCreate bc -> assign (env . contracts . at r) (Just $ initialContract (InitCode (ConcreteBuffer bc)) & set balance v) >> loadContract r >> state . code .= ConcreteBuffer bc
SolCall ("*receive*",_) -> incrementBalance >> loadContract r >> state . calldata .= concreteCalldata ""
SolCall ("*fallback*",_) -> incrementBalance >> loadContract r >> state . calldata .= concreteCalldata "\0"
SolCall cd -> incrementBalance >> loadContract r >> state . calldata .= concreteCalldata (encode cd)
SolCalldata cd -> incrementBalance >> loadContract r >> state . calldata .= concreteCalldata cd
NoCall -> error "NoCall"
incrementBalance = (env . contracts . ix r . balance) += v
encode (n, vs) = abiCalldata
(encodeSig (n, abiValueType <$> vs)) $ V.fromList vs
Expand Down
2 changes: 0 additions & 2 deletions src/test/Tests/Integration.hs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@ integrationTests = testGroup "Solidity Integration Testing"
[ ("echidna_library_call failed", solved "echidna_library_call")
, ("echidna_valid_timestamp failed", passed "echidna_valid_timestamp")
]
, testContractV "basic/fallback.sol" (Just (< solcV (0,6,0))) Nothing
[ ("echidna_fallback failed", solved "echidna_fallback") ]
, testContract "basic/push_long.sol" (Just "basic/push_long.yaml")
[ ("test_long_5 passed", solvedWithout NoCall "test_long_5")]
, testContract "basic/propGasLimit.sol" (Just "basic/propGasLimit.yaml")
Expand Down
6 changes: 4 additions & 2 deletions src/test/Tests/Values.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Tests.Values (valuesTests) where

import Test.Tasty (TestTree, testGroup)

import Common (testContract, testContract', solved, solvedLen)
import Common (testContract, testContract', testContractV, solcV, solved, solvedLen)

valuesTests :: TestTree
valuesTests = testGroup "Value extraction tests"
Expand Down Expand Up @@ -33,5 +33,7 @@ valuesTests = testGroup "Value extraction tests"
, testContract "values/darray.sol" Nothing
[ ("echidna_darray passed", solved "echidna_darray")
, ("echidna_darray didn't shrink optimally", solvedLen 1 "echidna_darray") ]

, testContractV "values/receive.sol" (Just (>= solcV (0,6,0))) Nothing
[ ("echidna_fallback failed", solved "echidna_fallback")
, ("echidna_receive failed", solved "echidna_receive") ]
]
22 changes: 22 additions & 0 deletions tests/solidity/values/receive.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pragma solidity ^0.6.0;

contract Receive {
bool found_fallback = false;
bool found_receive = false;

function echidna_found_fallback() public view returns (bool) {
return(!found_fallback);
}

function echidna_found_receive() public view returns (bool) {
return(!found_receive);
}

fallback() external payable {
found_fallback = true;
}

receive() external payable {
found_receive = true;
}
}