-
Notifications
You must be signed in to change notification settings - Fork 478
Commit
* Add assertions to auto test gen * Add symbolic tests * Make calldata symbolic * EVM: Support exp aka pow (#1361) * EVM: Add support for EXP with concrete/solvable exponent Adds support for EXP aka POW, with concrete or solvable exponent, fixing #1005 effectively. Not sure if we can do it any better - it seems z3 doesn't have exp/pow for bitvectors. * Update operators.py * Update evm.py * Use concretized_args * Move Operators.POW to EVM._exp * Extend travis wait for output to 30m * Extend travis build to 60m... * Fix Operators.ITE -> Operators.ITEBV * Split ethereum travis job to two jobs * EVM.EXP: concretize base=SAMPLED * Fix concrete tests: use to_constant * Fix set storage in concrete tests * Split ethereum_vm tests into concrete and symbolic * Fix travis tests * Split symbolic tests into two jobs * Split VMTests even more * More tests split * [WIP][WIP][WIP] Moving executor functionality to ManticoreBase and refactor concurrency shared data * Workspace locks * Concurrency flavor configurable from commandline * Asserts and refactorrrrrrrs * Remove unused callback * Some CC * Some CC * Some CC * Fix solver vs Z3Solver * Make solver a singleton based on tid/pid. REfactor m._save. Fix some tests * typo and evm bugfix * Fix some tests referecing global solver * Fix concolic tests and more global solver refs * Fix tests * CC fixes * Fix tests. Fix testcase id generation * Move profiling to a plugin and fix tests * Add solver intance ref to mem test * Fix mem workspace tests * Fix output checking tests * Fix z3solver ref * Relax verbosity/log tests * Moved Workers to its own file * Relax output tests * Relax output tests * Fix profiling test * Fix more tests * Default multiprocessing * Try to clean mcore __del__ * Change Worker life span * Fix Single mode * CC * revert verbosity travis * CC and solver ref fix * Relax ouput checking tests and some bugfixes * running -> ready * Fixing teeests * add weak cache to _load * del debug prints * Adding config.py support for Enums * Try/Remove generate_testcase event as it never occurs online. Fix tests * Fix CC * Kill the cache when start/stop run. Remove debugprints. clean tests * Fix travis test _other_ * Fix native tests and timeout * Fix state.must_be_true * fix CC * Changing fstat tets...: ~' * LLLLLLLLinux tests * Skip unicorn concrete test for now * Try fix CodeClimate * Try fix CodeClimate * Update evm examples to newest solidity * Complete transformation of consts.mprocessing to enum * Add blank line (codeclimate) * Using the enum instead of the string * Using the enum instead of the string * Merge and fix * CC and debug print * Move fee consumption to checkpoint so it is not done twice. Fix frontier test generator * Fix Job Count (and force travis rebuild) ``` 0.02s$ ./cc-test-reporter sum-coverage --output - --parts $JOB_COUNT coverage/codeclimate.*.json | ./cc-test-reporter upload-coverage --input - Error: expected 3 parts, received 4 parts ``` * Add tx number to testcase log * Del test verbosity
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import sys | ||
|
||
import os | ||
|
||
|
||
def compare_traces(dir1: str, dir2: str): | ||
""" | ||
Compare state traces from two mcore_* directories. | ||
For now assumes to use `test_xxxxxxx.trace` only. | ||
""" | ||
get_traces = lambda dir: [f for f in os.listdir(dir) if f.startswith('test_') and f.endswith('.trace')] | ||
|
||
traces1 = get_traces(dir1) | ||
traces2 = get_traces(dir2) | ||
|
||
traces1.sort() | ||
traces2.sort() | ||
|
||
print("### Comparing traces: ") | ||
print(f"dir1 - {dir1} :") | ||
print(', '.join(traces1)) | ||
print() | ||
print(f"dir2 - {dir2} :") | ||
print(', '.join(traces2)) | ||
|
||
for t1, t2 in zip(traces1, traces2): | ||
path1 = os.path.join(dir1, t1) | ||
path2 = os.path.join(dir2, t2) | ||
|
||
with open(path1) as fp1, open(path2) as fp2: | ||
if fp1.read() != fp2.read(): | ||
print(f'Files {t1} and {t2} differs.') | ||
else: | ||
print(f'Files {t1} and {t2} matches.') | ||
|
||
|
||
if __name__ == '__main__': | ||
if len(sys.argv) != 3: | ||
print(f'Usage: {sys.argv[0]} MCORE_DIR_1 MCORE_DIR_2') | ||
sys.exit() | ||
|
||
dir1, dir2 = sys.argv[1:] | ||
|
||
not_dir = lambda d: not os.path.isdir(d) | ||
|
||
if not_dir(dir1) or not_dir(dir2): | ||
print('One of passed args is not a directory!') | ||
sys.exit(-1) | ||
|
||
compare_traces(dir1, dir2) |
Large diffs are not rendered by default.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# DO NOT DELETE |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
"""DO NOT MODIFY: Tests generated from `VMTests/vmTests` with make_VMTests.py""" | ||
import unittest | ||
from binascii import unhexlify | ||
|
||
import rlp | ||
import sha3 | ||
from rlp.sedes import ( | ||
CountableList, | ||
BigEndianInt, | ||
Binary, | ||
) | ||
|
||
from manticore.core.smtlib import ConstraintSet, Z3Solver # Ignore unused import in non-symbolic tests! | ||
from manticore.core.smtlib.visitors import to_constant | ||
from manticore.platforms import evm | ||
from manticore.utils import config | ||
from manticore.core.state import Concretize | ||
|
||
|
||
|
||
class Log(rlp.Serializable): | ||
fields = [ | ||
('address', Binary.fixed_length(20, allow_empty=True)), | ||
('topics', CountableList(BigEndianInt(32))), | ||
('data', Binary()) | ||
] | ||
|
||
|
||
class EVMTest_vmTests(unittest.TestCase): | ||
# https://nose.readthedocs.io/en/latest/doc_tests/test_multiprocess/multiprocess.html#controlling-distribution | ||
_multiprocess_can_split_ = True | ||
# https://docs.python.org/3.7/library/unittest.html#unittest.TestCase.maxDiff | ||
maxDiff = None | ||
|
||
SAVED_DEFAULT_FORK = evm.DEFAULT_FORK | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
consts = config.get_group('evm') | ||
consts.oog = 'pedantic' | ||
evm.DEFAULT_FORK = 'frontier' | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
evm.DEFAULT_FORK = cls.SAVED_DEFAULT_FORK | ||
|
||
def _test_run(self, world): | ||
result = None | ||
returndata = b'' | ||
try: | ||
while True: | ||
try: | ||
world.current_vm.execute() | ||
except Concretize as e: | ||
value = self._solve(world.constraints, e.expression) | ||
class fake_state:pass | ||
fake_state = fake_state() | ||
fake_state.platform = world | ||
e.setstate(fake_state, value) | ||
except evm.EndTx as e: | ||
result = e.result | ||
if result in ('RETURN', 'REVERT'): | ||
returndata = self._solve(world.constraints, e.data) | ||
except evm.StartTx as e: | ||
self.fail('This tests should not initiate an internal tx (no CALLs allowed)') | ||
return result, returndata | ||
|
||
def _solve(self, constraints, val): | ||
results = Z3Solver.instance().get_all_values(constraints, val, maxcnt=3) | ||
# We constrain all values to single values! | ||
self.assertEqual(len(results), 1) | ||
return results[0] | ||
|
||
|
||
def test_suicide(self): | ||
""" | ||
Testcase taken from https://github.com/ethereum/tests | ||
File: suicide.json | ||
sha256sum: 1aa0a61de3c9576faf6ac4f002626210a5315d3132d032162b2934d304a60c1f | ||
Code: CALLER | ||
SELFDESTRUCT | ||
""" | ||
|
||
def solve(val): | ||
""" | ||
Those tests are **auto-generated** and `solve` is used in symbolic tests. | ||
So yes, this returns just val; it makes it easier to generate tests like this. | ||
""" | ||
return to_constant(val) | ||
|
||
constraints = ConstraintSet() | ||
|
||
blocknumber = 0 | ||
timestamp = 1 | ||
difficulty = 256 | ||
coinbase = 244687034288125203496486448490407391986876152250 | ||
gaslimit = 1000000 | ||
world = evm.EVMWorld(constraints, blocknumber=blocknumber, timestamp=timestamp, difficulty=difficulty, | ||
coinbase=coinbase, gaslimit=gaslimit) | ||
|
||
acc_addr = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6 | ||
acc_code = unhexlify('33ff') | ||
acc_balance = 100000000000000000000000 | ||
acc_nonce = 0 | ||
|
||
world.create_account(address=acc_addr, balance=acc_balance, code=acc_code, nonce=acc_nonce) | ||
|
||
address = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6 | ||
caller = 0xcd1722f3947def4cf144679da39c4c32bdc35681 | ||
price = 0x5af3107a4000 | ||
value = 1000000000000000000 | ||
gas = 100000 | ||
data = '' | ||
# open a fake tx, no funds send | ||
world._open_transaction('CALL', address, price, data, caller, value, gas=gas) | ||
|
||
# This variable might seem redundant in some tests - don't forget it is auto generated | ||
# and there are cases in which we need it ;) | ||
result, returndata = self._test_run(world) | ||
|
||
# World sanity checks - those should not change, right? | ||
self.assertEqual(solve(world.block_number()), 0) | ||
self.assertEqual(solve(world.block_gaslimit()), 1000000) | ||
self.assertEqual(solve(world.block_timestamp()), 1) | ||
self.assertEqual(solve(world.block_difficulty()), 256) | ||
self.assertEqual(solve(world.block_coinbase()), 0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba) | ||
|
||
# Add post checks for account 0xcd1722f3947def4cf144679da39c4c32bdc35681 | ||
# check nonce, balance, code | ||
self.assertEqual(solve(world.get_nonce(0xcd1722f3947def4cf144679da39c4c32bdc35681)), 0) | ||
self.assertEqual(solve(world.get_balance(0xcd1722f3947def4cf144679da39c4c32bdc35681)), 100000000000000000000000) | ||
self.assertEqual(world.get_code(0xcd1722f3947def4cf144679da39c4c32bdc35681), unhexlify('')) | ||
# check outs | ||
self.assertEqual(returndata, unhexlify('')) | ||
# check logs | ||
logs = [Log(unhexlify('{:040x}'.format(l.address)), l.topics, solve(l.memlog)) for l in world.logs] | ||
data = rlp.encode(logs) | ||
self.assertEqual(sha3.keccak_256(data).hexdigest(), '1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347') | ||
|
||
# test used gas | ||
self.assertEqual(solve(world.current_vm.gas), 99998) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# DO NOT DELETE |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
"""DO NOT MODIFY: Tests generated from `VMTests/vmTests` with make_VMTests.py""" | ||
import unittest | ||
from binascii import unhexlify | ||
|
||
import rlp | ||
import sha3 | ||
from rlp.sedes import ( | ||
CountableList, | ||
BigEndianInt, | ||
Binary, | ||
) | ||
|
||
from manticore.core.smtlib import ConstraintSet, Z3Solver # Ignore unused import in non-symbolic tests! | ||
from manticore.core.smtlib.visitors import to_constant | ||
from manticore.platforms import evm | ||
from manticore.utils import config | ||
from manticore.core.state import Concretize | ||
|
||
|
||
|
||
class Log(rlp.Serializable): | ||
fields = [ | ||
('address', Binary.fixed_length(20, allow_empty=True)), | ||
('topics', CountableList(BigEndianInt(32))), | ||
('data', Binary()) | ||
] | ||
|
||
|
||
class EVMTest_vmTests(unittest.TestCase): | ||
# https://nose.readthedocs.io/en/latest/doc_tests/test_multiprocess/multiprocess.html#controlling-distribution | ||
_multiprocess_can_split_ = True | ||
# https://docs.python.org/3.7/library/unittest.html#unittest.TestCase.maxDiff | ||
maxDiff = None | ||
|
||
SAVED_DEFAULT_FORK = evm.DEFAULT_FORK | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
consts = config.get_group('evm') | ||
consts.oog = 'pedantic' | ||
evm.DEFAULT_FORK = 'frontier' | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
evm.DEFAULT_FORK = cls.SAVED_DEFAULT_FORK | ||
|
||
def _test_run(self, world): | ||
result = None | ||
returndata = b'' | ||
try: | ||
while True: | ||
try: | ||
world.current_vm.execute() | ||
except Concretize as e: | ||
value = self._solve(world.constraints, e.expression) | ||
class fake_state:pass | ||
fake_state = fake_state() | ||
fake_state.platform = world | ||
e.setstate(fake_state, value) | ||
except evm.EndTx as e: | ||
result = e.result | ||
if result in ('RETURN', 'REVERT'): | ||
returndata = self._solve(world.constraints, e.data) | ||
except evm.StartTx as e: | ||
self.fail('This tests should not initiate an internal tx (no CALLs allowed)') | ||
return result, returndata | ||
|
||
def _solve(self, constraints, val): | ||
results = Z3Solver.instance().get_all_values(constraints, val, maxcnt=3) | ||
# We constrain all values to single values! | ||
self.assertEqual(len(results), 1) | ||
return results[0] | ||
|
||
|
||
def test_suicide(self): | ||
""" | ||
Testcase taken from https://github.com/ethereum/tests | ||
File: suicide.json | ||
sha256sum: 1aa0a61de3c9576faf6ac4f002626210a5315d3132d032162b2934d304a60c1f | ||
Code: CALLER | ||
SELFDESTRUCT | ||
""" | ||
|
||
def solve(val): | ||
return self._solve(constraints, val) | ||
|
||
constraints = ConstraintSet() | ||
|
||
blocknumber = constraints.new_bitvec(256, name='blocknumber') | ||
constraints.add(blocknumber == 0) | ||
|
||
timestamp = constraints.new_bitvec(256, name='timestamp') | ||
constraints.add(timestamp == 1) | ||
|
||
difficulty = constraints.new_bitvec(256, name='difficulty') | ||
constraints.add(difficulty == 256) | ||
|
||
coinbase = constraints.new_bitvec(256, name='coinbase') | ||
constraints.add(coinbase == 244687034288125203496486448490407391986876152250) | ||
|
||
gaslimit = constraints.new_bitvec(256, name='gaslimit') | ||
constraints.add(gaslimit == 1000000) | ||
|
||
world = evm.EVMWorld(constraints, blocknumber=blocknumber, timestamp=timestamp, difficulty=difficulty, | ||
coinbase=coinbase, gaslimit=gaslimit) | ||
|
||
acc_addr = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6 | ||
acc_code = unhexlify('33ff') | ||
|
||
acc_balance = constraints.new_bitvec(256, name='balance_0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6') | ||
constraints.add(acc_balance == 100000000000000000000000) | ||
|
||
acc_nonce = constraints.new_bitvec(256, name='nonce_0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6') | ||
constraints.add(acc_nonce == 0) | ||
|
||
world.create_account(address=acc_addr, balance=acc_balance, code=acc_code, nonce=acc_nonce) | ||
|
||
address = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6 | ||
caller = 0xcd1722f3947def4cf144679da39c4c32bdc35681 | ||
price = constraints.new_bitvec(256, name='price') | ||
constraints.add(price == 100000000000000) | ||
|
||
value = constraints.new_bitvec(256, name='value') | ||
constraints.add(value == 1000000000000000000) | ||
|
||
gas = constraints.new_bitvec(256, name='gas') | ||
constraints.add(gas == 100000) | ||
|
||
data = '' | ||
# open a fake tx, no funds send | ||
world._open_transaction('CALL', address, price, data, caller, value, gas=gas) | ||
|
||
# This variable might seem redundant in some tests - don't forget it is auto generated | ||
# and there are cases in which we need it ;) | ||
result, returndata = self._test_run(world) | ||
|
||
# World sanity checks - those should not change, right? | ||
self.assertEqual(solve(world.block_number()), 0) | ||
self.assertEqual(solve(world.block_gaslimit()), 1000000) | ||
self.assertEqual(solve(world.block_timestamp()), 1) | ||
self.assertEqual(solve(world.block_difficulty()), 256) | ||
self.assertEqual(solve(world.block_coinbase()), 0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba) | ||
|
||
# Add post checks for account 0xcd1722f3947def4cf144679da39c4c32bdc35681 | ||
# check nonce, balance, code | ||
self.assertEqual(solve(world.get_nonce(0xcd1722f3947def4cf144679da39c4c32bdc35681)), 0) | ||
self.assertEqual(solve(world.get_balance(0xcd1722f3947def4cf144679da39c4c32bdc35681)), 100000000000000000000000) | ||
self.assertEqual(world.get_code(0xcd1722f3947def4cf144679da39c4c32bdc35681), unhexlify('')) | ||
# check outs | ||
self.assertEqual(returndata, unhexlify('')) | ||
# check logs | ||
logs = [Log(unhexlify('{:040x}'.format(l.address)), l.topics, solve(l.memlog)) for l in world.logs] | ||
data = rlp.encode(logs) | ||
self.assertEqual(sha3.keccak_256(data).hexdigest(), '1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347') | ||
|
||
# test used gas | ||
self.assertEqual(solve(world.current_vm.gas), 99998) | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |