From b928eeebd4d59d537d5edcd5275579958aa7e896 Mon Sep 17 00:00:00 2001 From: Beau Gunderson Date: Sat, 8 Jul 2017 00:03:24 -0700 Subject: [PATCH] make oyente pip-installable --- .gitignore | 22 +++++++---- CONTRIBUTING.md | 2 +- README.md | 2 +- code.md | 2 +- {test_evm => oyente}/__init__.py | 0 analysis.py => oyente/analysis.py | 0 assertion.py => oyente/assertion.py | 0 basicblock.py => oyente/basicblock.py | 0 batch_run.py => oyente/batch_run.py | 0 ethereum_data.py => oyente/ethereum_data.py | 0 ethereum_data1.py => oyente/ethereum_data1.py | 0 global_params.py => oyente/global_params.py | 0 opcodes.py => oyente/opcodes.py | 0 oyente.py => oyente/oyente.py | 2 + test_evm.py => oyente/run_tests.py | 35 +++++++++++++---- state.json => oyente/state.json | 0 symExec.py => oyente/symExec.py | 6 ++- oyente/test_evm/__init__.py | 0 .../test_evm}/evm_unit_test.py | 8 ++-- .../test_evm}/global_test_params.py | 2 + .../test_evm}/test_data/vmArithmeticTest.json | 0 .../vmBitwiseLogicOperationTest.json | 0 .../test_data/vmPushDupSwapTest.json | 0 utils.py => oyente/utils.py | 0 vargenerator.py => oyente/vargenerator.py | 0 setup.py | 39 +++++++++++++++++++ 26 files changed, 97 insertions(+), 23 deletions(-) rename {test_evm => oyente}/__init__.py (100%) rename analysis.py => oyente/analysis.py (100%) rename assertion.py => oyente/assertion.py (100%) rename basicblock.py => oyente/basicblock.py (100%) rename batch_run.py => oyente/batch_run.py (100%) rename ethereum_data.py => oyente/ethereum_data.py (100%) rename ethereum_data1.py => oyente/ethereum_data1.py (100%) rename global_params.py => oyente/global_params.py (100%) rename opcodes.py => oyente/opcodes.py (100%) rename oyente.py => oyente/oyente.py (99%) rename test_evm.py => oyente/run_tests.py (79%) mode change 100644 => 100755 rename state.json => oyente/state.json (100%) rename symExec.py => oyente/symExec.py (99%) create mode 100644 oyente/test_evm/__init__.py rename {test_evm => oyente/test_evm}/evm_unit_test.py (98%) rename {test_evm => oyente/test_evm}/global_test_params.py (75%) rename {test_evm => oyente/test_evm}/test_data/vmArithmeticTest.json (100%) rename {test_evm => oyente/test_evm}/test_data/vmBitwiseLogicOperationTest.json (100%) rename {test_evm => oyente/test_evm}/test_data/vmPushDupSwapTest.json (100%) rename utils.py => oyente/utils.py (100%) rename vargenerator.py => oyente/vargenerator.py (100%) create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index e1b69fc3..b297dc31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,19 @@ -tmp/ -tmp -*.pyc -contract_data -*.sol +*.disasm *.evm *.log -*.disasm +*.pyc *.report +*.sol + .DS_Store -.idea/ \ No newline at end of file + +.idea/dist/ + +contract_data +dist/ +tmp/ + +current_test.pickle + +bytecode +bytecode.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b85282b3..35fa7cb9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ UNIT_TEST = 3 ``` # Start testing -$ python test_evm.py +$ python oyenete/run_tests.py ``` After running the testing program, the result would display a status for each testcase: diff --git a/README.md b/README.md index 0c69ddeb..fc89a97d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Note - If need the [version of Oyente](https://github.com/melonproject/oyente/tr ## Full install ### Install the following dependencies -#### solc v0.4.10 +#### solc v0.4.13 ``` $ sudo add-apt-repository ppa:ethereum/ethereum $ sudo apt-get update diff --git a/code.md b/code.md index 8a63e639..e6abfafa 100644 --- a/code.md +++ b/code.md @@ -85,7 +85,7 @@ The flow of testing: - Compare the results (storage, memory and gas) after running oyente with the results being specified in the test data - Report bugs -#### *test_evm.py* +#### *run_tests.py* This is the main entry point to the testing program. The program loads a specific test data file in folder ```test_evm/test_data/``` and start running `oyente.py `with the input being specified in the loaded test data to get an exit code which is returned from `oyente.py.` From this exit code the testing program can report the bug #### *evm_unit_test.py* diff --git a/test_evm/__init__.py b/oyente/__init__.py similarity index 100% rename from test_evm/__init__.py rename to oyente/__init__.py diff --git a/analysis.py b/oyente/analysis.py similarity index 100% rename from analysis.py rename to oyente/analysis.py diff --git a/assertion.py b/oyente/assertion.py similarity index 100% rename from assertion.py rename to oyente/assertion.py diff --git a/basicblock.py b/oyente/basicblock.py similarity index 100% rename from basicblock.py rename to oyente/basicblock.py diff --git a/batch_run.py b/oyente/batch_run.py similarity index 100% rename from batch_run.py rename to oyente/batch_run.py diff --git a/ethereum_data.py b/oyente/ethereum_data.py similarity index 100% rename from ethereum_data.py rename to oyente/ethereum_data.py diff --git a/ethereum_data1.py b/oyente/ethereum_data1.py similarity index 100% rename from ethereum_data1.py rename to oyente/ethereum_data1.py diff --git a/global_params.py b/oyente/global_params.py similarity index 100% rename from global_params.py rename to oyente/global_params.py diff --git a/opcodes.py b/oyente/opcodes.py similarity index 100% rename from opcodes.py rename to oyente/opcodes.py diff --git a/oyente.py b/oyente/oyente.py similarity index 99% rename from oyente.py rename to oyente/oyente.py index 4ed01978..1396ea8b 100755 --- a/oyente.py +++ b/oyente/oyente.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + import shlex import subprocess import os diff --git a/test_evm.py b/oyente/run_tests.py old mode 100644 new mode 100755 similarity index 79% rename from test_evm.py rename to oyente/run_tests.py index 86884deb..8c1737bd --- a/test_evm.py +++ b/oyente/run_tests.py @@ -1,10 +1,18 @@ -import json +#!/usr/bin/env python + import glob +import json import os import pickle -from test_evm.global_test_params import * + +os.chdir(os.path.dirname(__file__)) + +from test_evm.global_test_params import ( + PASS, FAIL, TIME_OUT, UNKOWN_INSTRUCTION, EXCEPTION, EMPTY_RESULT, + INCORRECT_GAS, PICKLE_PATH) from test_evm.evm_unit_test import EvmUnitTest + def status(exit_code): if exit_code == 100: return "Pass" if exit_code == 101: return "Fail" @@ -14,13 +22,15 @@ def status(exit_code): if exit_code == 105: return "Empty result" if exit_code == 106: return "Incorrect gas tracked" + return str(exit_code) + def main(): test_dir = 'test_evm/test_data' - files = glob.glob(test_dir+'/vmArithmeticTest.json') + files = glob.glob(test_dir + '/vmArithmeticTest.json') test_cases = {} - num_tests = num_passes = num_fails = \ + num_tests = num_passes = num_fails = \ num_time_outs = num_unkown_instrs = \ num_exceptions = num_empty_res = num_incorrect_gas = 0 @@ -40,14 +50,19 @@ def main(): print "===============Loading: %s====================" % testname current_test = EvmUnitTest(testname, testdata) - pickle.dump(current_test, open("current_test.pickle", "wb")) + + pickle.dump(current_test, open(PICKLE_PATH, 'wb'), pickle.HIGHEST_PROTOCOL) exit_code = current_test.run_test() + # Special case when symExec run into exception but it is correct result if exit_code == EXCEPTION and current_test.is_exception_case(): exit_code = PASS - print "===============%s!====================" % status(exit_code).upper() + if exit_code: + print "===============%s!====================" % status(exit_code).upper() + else: + print "no exit code returned" testname = testname.encode('utf8') num_tests += 1 @@ -93,8 +108,12 @@ def main(): def remove_temporary_files(): - if os.path.isfile("./bytecode"): os.system("rm bytecode") - if os.path.isfile("./current_test.pickle"): os.system("rm current_test.pickle") + if os.path.isfile('./bytecode'): + os.unlink('./bytecode') + + if os.path.isfile(PICKLE_PATH): + os.unlink(PICKLE_PATH) + if __name__ == '__main__': main() diff --git a/state.json b/oyente/state.json similarity index 100% rename from state.json rename to oyente/state.json diff --git a/symExec.py b/oyente/symExec.py similarity index 99% rename from symExec.py rename to oyente/symExec.py index edfbe2ca..f6db9ab3 100755 --- a/symExec.py +++ b/oyente/symExec.py @@ -21,7 +21,9 @@ from analysis import * from utils import retrieveFunctionSignatures, retrieveFunctionNames import global_params -from test_evm.global_test_params import * + +from test_evm.global_test_params import (TIME_OUT, UNKOWN_INSTRUCTION, + EXCEPTION, PICKLE_PATH) log = logging.getLogger(__name__) @@ -126,7 +128,7 @@ def compare_stack_unit_test(stack): log.warning(e.message) def compare_storage_and_memory_unit_test(global_state, mem, analysis): - unit_test = pickle.load(open("current_test.pickle", "rb")) + unit_test = pickle.load(open(PICKLE_PATH, 'rb')) test_status = unit_test.compare_with_symExec_result(global_state, mem, analysis) exit(test_status) diff --git a/oyente/test_evm/__init__.py b/oyente/test_evm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test_evm/evm_unit_test.py b/oyente/test_evm/evm_unit_test.py similarity index 98% rename from test_evm/evm_unit_test.py rename to oyente/test_evm/evm_unit_test.py index 75eb0bfb..8b04b01c 100644 --- a/test_evm/evm_unit_test.py +++ b/oyente/test_evm/evm_unit_test.py @@ -1,9 +1,13 @@ import os + from z3 import * -from global_test_params import * + from global_params import * from utils import to_unsigned +from .global_test_params import * + + class EvmUnitTest(object): def __init__(self, name, data): self.name = name @@ -28,7 +32,6 @@ def gas_info(self): gas_remaining = long(self.data['gas'], 0) return (gas_limit, gas_remaining) - def run_test(self): return self._execute_vm(self.bytecode()) @@ -86,7 +89,6 @@ def _compare_gas_value(self, analysis): else: return INCORRECT_GAS - def compare_symbolic(self, global_state): for key, value in self.storage().items(): key, value = long(key, 0), long(value, 0) diff --git a/test_evm/global_test_params.py b/oyente/test_evm/global_test_params.py similarity index 75% rename from test_evm/global_test_params.py rename to oyente/test_evm/global_test_params.py index 6b2a79d6..d288b89e 100644 --- a/test_evm/global_test_params.py +++ b/oyente/test_evm/global_test_params.py @@ -5,3 +5,5 @@ EXCEPTION = 104 EMPTY_RESULT = 105 INCORRECT_GAS = 106 + +PICKLE_PATH = 'current_test.pickle' diff --git a/test_evm/test_data/vmArithmeticTest.json b/oyente/test_evm/test_data/vmArithmeticTest.json similarity index 100% rename from test_evm/test_data/vmArithmeticTest.json rename to oyente/test_evm/test_data/vmArithmeticTest.json diff --git a/test_evm/test_data/vmBitwiseLogicOperationTest.json b/oyente/test_evm/test_data/vmBitwiseLogicOperationTest.json similarity index 100% rename from test_evm/test_data/vmBitwiseLogicOperationTest.json rename to oyente/test_evm/test_data/vmBitwiseLogicOperationTest.json diff --git a/test_evm/test_data/vmPushDupSwapTest.json b/oyente/test_evm/test_data/vmPushDupSwapTest.json similarity index 100% rename from test_evm/test_data/vmPushDupSwapTest.json rename to oyente/test_evm/test_data/vmPushDupSwapTest.json diff --git a/utils.py b/oyente/utils.py similarity index 100% rename from utils.py rename to oyente/utils.py diff --git a/vargenerator.py b/oyente/vargenerator.py similarity index 100% rename from vargenerator.py rename to oyente/vargenerator.py diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..d9d3842e --- /dev/null +++ b/setup.py @@ -0,0 +1,39 @@ +from setuptools import find_packages, setup + +setup( + name='oyente', + version='1.0.0', + author='Loi Luu', + # author_email='', + url='https://github.com/melonport/oyente', + description='An analysis tool for smart contracts', + long_description=open('README.md').read(), + license='GPL', + keywords='ethereum smart contracts', + classifiers=[ + 'Environment :: Console', + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: BSD License', + 'Operating System :: POSIX', + 'Operating System :: MacOS :: MacOS X', + 'Programming Language :: Python', + 'Topic :: Utilities', + ], + packages=find_packages(), + package_data={ + 'oyente': ['state.json'], + }, + entry_points={ + 'console_scripts': [ + 'oyente = oyente.oyente:main', + ] + }, + install_requires=[ + 'requests', + 'web3', + ] +)