mirror of https://github.com/ConsenSys/mythril
Merge branch 'master' of https://github.com/ConsenSys/mythril
commit
5763ebf1e6
@ -1,13 +0,0 @@ |
||||
[run] |
||||
source = |
||||
. |
||||
|
||||
[report] |
||||
omit = |
||||
*__init__.py |
||||
/usr/* |
||||
*_test.py |
||||
setup.py |
||||
|
||||
[html] |
||||
directory = coverage_html_report |
@ -0,0 +1,16 @@ |
||||
--- |
||||
name: Analysis module |
||||
about: Create an analysis module feature request |
||||
|
||||
--- |
||||
|
||||
# Detection issue: |
||||
Name the issue that should be detected using the analysis module |
||||
|
||||
## Description: |
||||
Provide a detailed description of the vulnerabiltity that should be detected |
||||
|
||||
## Link |
||||
Provide resources that can help with implementing the analysis module |
||||
|
||||
## Implementation details:Initial implementation ideas/instruction |
@ -0,0 +1,28 @@ |
||||
--- |
||||
name: Bug report |
||||
about: Create a report to help us improve |
||||
|
||||
--- |
||||
|
||||
**Describe the bug** |
||||
A clear and concise description of what the bug is. |
||||
|
||||
**To Reproduce** |
||||
Steps to reproduce the behavior: |
||||
1. Go to '...' |
||||
2. Click on '....' |
||||
3. Scroll down to '....' |
||||
4. See error |
||||
|
||||
**Expected behavior** |
||||
A clear and concise description of what you expected to happen. |
||||
|
||||
**Screenshots** |
||||
If applicable, add screenshots to help explain your problem. |
||||
|
||||
**Desktop (please complete the following information):** |
||||
- OS: [e.g. iOS] |
||||
- Version [e.g. 22] |
||||
|
||||
**Additional context** |
||||
Add any other context about the problem here. |
@ -1,20 +1,182 @@ |
||||
.DS_Store |
||||
|
||||
# Created by https://www.gitignore.io/api/linux,macos,python,windows |
||||
|
||||
### Linux ### |
||||
*~ |
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file |
||||
.fuse_hidden* |
||||
|
||||
# KDE directory preferences |
||||
.directory |
||||
|
||||
# Linux trash folder which might appear on any partition or disk |
||||
.Trash-* |
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed |
||||
.nfs* |
||||
|
||||
### macOS ### |
||||
*.DS_Store |
||||
.AppleDouble |
||||
.LSOverride |
||||
|
||||
# Icon must end with two \r |
||||
Icon |
||||
|
||||
# Thumbnails |
||||
._* |
||||
|
||||
# Files that might appear in the root of a volume |
||||
.DocumentRevisions-V100 |
||||
.fseventsd |
||||
.Spotlight-V100 |
||||
.TemporaryItems |
||||
.Trashes |
||||
.VolumeIcon.icns |
||||
.com.apple.timemachine.donotpresent |
||||
|
||||
# Directories potentially created on remote AFP share |
||||
.AppleDB |
||||
.AppleDesktop |
||||
Network Trash Folder |
||||
Temporary Items |
||||
.apdisk |
||||
|
||||
### Python ### |
||||
# Byte-compiled / optimized / DLL files |
||||
__pycache__/ |
||||
*.py[cod] |
||||
*$py.class |
||||
|
||||
# C extensions |
||||
*.so |
||||
|
||||
# Distribution / packaging |
||||
.Python |
||||
build/ |
||||
develop-eggs/ |
||||
dist/ |
||||
downloads/ |
||||
eggs/ |
||||
.eggs/ |
||||
lib/ |
||||
lib64/ |
||||
parts/ |
||||
sdist/ |
||||
var/ |
||||
wheels/ |
||||
*.egg-info/ |
||||
.installed.cfg |
||||
*.egg |
||||
|
||||
# PyInstaller |
||||
# Usually these files are written by a python script from a template |
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it. |
||||
*.manifest |
||||
*.spec |
||||
|
||||
# Installer logs |
||||
pip-log.txt |
||||
pip-delete-this-directory.txt |
||||
|
||||
# Unit test / coverage reports |
||||
htmlcov/ |
||||
.tox/ |
||||
.coverage |
||||
.coverage.* |
||||
.cache |
||||
.pytest_cache/ |
||||
nosetests.xml |
||||
coverage.xml |
||||
*.cover |
||||
.hypothesis/ |
||||
|
||||
# Translations |
||||
*.mo |
||||
*.pot |
||||
|
||||
# Flask stuff: |
||||
instance/ |
||||
.webassets-cache |
||||
|
||||
# Scrapy stuff: |
||||
.scrapy |
||||
|
||||
# Sphinx documentation |
||||
docs/_build/ |
||||
|
||||
# PyBuilder |
||||
target/ |
||||
|
||||
# Jupyter Notebook |
||||
.ipynb_checkpoints |
||||
|
||||
# pyenv |
||||
.python-version |
||||
__pycache__ |
||||
*.pyc |
||||
|
||||
# celery beat schedule file |
||||
celerybeat-schedule.* |
||||
|
||||
# SageMath parsed files |
||||
*.sage.py |
||||
|
||||
# Environments |
||||
.env |
||||
.venv |
||||
env/ |
||||
venv/ |
||||
ENV/ |
||||
env.bak/ |
||||
venv.bak/ |
||||
|
||||
# Spyder project settings |
||||
.spyderproject |
||||
.spyproject |
||||
|
||||
# Rope project settings |
||||
.ropeproject |
||||
|
||||
# mkdocs documentation |
||||
/site |
||||
|
||||
# mypy |
||||
.mypy_cache/ |
||||
|
||||
### Windows ### |
||||
# Windows thumbnail cache files |
||||
Thumbs.db |
||||
ehthumbs.db |
||||
ehthumbs_vista.db |
||||
|
||||
# Folder config file |
||||
Desktop.ini |
||||
|
||||
# Recycle Bin used on file shares |
||||
$RECYCLE.BIN/ |
||||
|
||||
# Windows Installer files |
||||
*.cab |
||||
*.msi |
||||
*.msm |
||||
*.msp |
||||
|
||||
# Windows shortcuts |
||||
*.lnk |
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/linux,macos,python,windows |
||||
|
||||
*.asm |
||||
mythril.egg-info |
||||
build |
||||
dist |
||||
*.rst |
||||
*.lock |
||||
!Pipfile.lock |
||||
*.svg |
||||
laser* |
||||
lol* |
||||
.idea* |
||||
coverage_html_report/ |
||||
.coverage |
||||
.pytest_cache |
||||
tests/testdata/outputs_current/ |
||||
tests/testdata/outputs_current_laser_result/ |
||||
tests/mythril_dir/signatures.json |
||||
|
||||
# VSCode |
||||
.vscode |
@ -0,0 +1,16 @@ |
||||
# Contributing to Mythril |
||||
Hi, if you are reading this that means that you probably want to contribute to Mythril, awesome! If not, then this file might not contain much useful information for you. |
||||
|
||||
## Creating an issue |
||||
If you have found a problem with Mythril or want to propose a new feature then you can do this using GitHub issues. |
||||
We already created some templates to make this process easier, but if your issue/feature request does not fit within the template then feel free to deviate. |
||||
|
||||
If you have a small question or aren't sure if you should create an issue for your problem/suggestion then you can always hop by on our [Gitter channel](https://gitter.im/ConsenSys/mythril). |
||||
|
||||
# Coding |
||||
If you want to help out with the development of Mythril then you can take a look at our issues or [Waffle board](https://waffle.io/ConsenSys/mythril). |
||||
|
||||
Before you start working on an issue pkease stop by on Gitter to message a collaborator, this way we can assign you to the issue making sure nobody does double work. We can also provide you with support through Gitter if there are any questions during the development process. |
||||
|
||||
## New ideas |
||||
Before you start working on a new idea, it's useful to create an issue on GitHub, that way we know what you want to implement and that you are working on it. Additionally, it might happen that your feature does not fit with our roadmap, in which case it would be unfortunate if you have already spent some time working on it. |
@ -1,19 +1,25 @@ |
||||
FROM ubuntu:rolling |
||||
FROM ubuntu:bionic |
||||
|
||||
COPY . . |
||||
COPY . /opt/mythril |
||||
|
||||
RUN apt-get update \ |
||||
&& apt-get install -y software-properties-common \ |
||||
&& apt-get install -y \ |
||||
build-essential \ |
||||
python-pip-whl=9.0.1-2 \ |
||||
python3-pip=9.0.1-2 \ |
||||
python3-setuptools \ |
||||
software-properties-common \ |
||||
&& add-apt-repository -y ppa:ethereum/ethereum \ |
||||
&& apt-get update \ |
||||
&& apt-get install -y solc \ |
||||
&& apt-get install -y libssl-dev \ |
||||
&& apt-get install -y python3-pip=9.0.1-2 python3-dev \ |
||||
&& apt-get install -y \ |
||||
solc \ |
||||
libssl-dev \ |
||||
python3-dev \ |
||||
pandoc \ |
||||
git \ |
||||
&& ln -s /usr/bin/python3 /usr/local/bin/python \ |
||||
# && pip3 install --upgrade pip \ |
||||
&& apt-get install -y pandoc \ |
||||
&& apt-get install -y git \ |
||||
&& cd /opt/mythril \ |
||||
&& pip3 install -r requirements.txt \ |
||||
&& python setup.py install |
||||
|
||||
CMD [] |
||||
ENTRYPOINT ["/usr/local/bin/myth"] |
||||
|
@ -1,2 +1,2 @@ |
||||
include mythril/disassembler/signatures.json |
||||
include mythril/analysis/templates/*.html |
||||
include mythril/analysis/templates/* |
||||
|
@ -1,716 +0,0 @@ |
||||
{ |
||||
"_meta": { |
||||
"hash": { |
||||
"sha256": "b8b7e52dd560311e7e06c0c51ab86c67503a1b7d7499e372ad00698acc16f43c" |
||||
}, |
||||
"pipfile-spec": 6, |
||||
"requires": { |
||||
"python_version": "3.6" |
||||
}, |
||||
"sources": [ |
||||
{ |
||||
"name": "pypi", |
||||
"url": "https://pypi.python.org/simple", |
||||
"verify_ssl": true |
||||
} |
||||
] |
||||
}, |
||||
"default": { |
||||
"asn1crypto": { |
||||
"hashes": [ |
||||
"sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87", |
||||
"sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49" |
||||
], |
||||
"version": "==0.24.0" |
||||
}, |
||||
"attrdict": { |
||||
"hashes": [ |
||||
"sha256:86aeb6d3809e0344409f8148d7cac9eabce5f0b577c160b5e90d10df3f8d2ad3" |
||||
], |
||||
"version": "==2.0.0" |
||||
}, |
||||
"attrs": { |
||||
"hashes": [ |
||||
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9", |
||||
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==17.4.0" |
||||
}, |
||||
"btrees": { |
||||
"hashes": [ |
||||
"sha256:46b02cb69b26a5238db771ea1955b503df73ecf254bb8063af4c61999fc75b5c", |
||||
"sha256:4986f7ea25013e0370d88a4699490f83da92745705001b3d619de7d9600edc66", |
||||
"sha256:4996f282254bc30ab3855df4b757a675d043edf069368ac8e9ac1fadcaebb89b", |
||||
"sha256:4c77eed4ae3e182de559296893ae00b8da3201d51c51751787b53b34ac3b1a79", |
||||
"sha256:888c016774630b7be2339888df1d0e7c91e1e0139e1b9ec80309feb1fc6fd9ec", |
||||
"sha256:895e5d173dd77989d8b9b9649e01a2509c6553ca3820c15f058e129fcbdab88c", |
||||
"sha256:a80c5f14eac095502b5ba6adfdbea7a891dc5d761efeef75d11c2dbed7a9e5f0", |
||||
"sha256:acfdd66a3db6753cec1a06345fbef27b4cc592e269dfc162fa1f881230d1addc", |
||||
"sha256:df8a059fc7c43ae34c47806be00021432988efdc8b24e8422fa6a785c9c78150" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==4.5.0" |
||||
}, |
||||
"certifi": { |
||||
"hashes": [ |
||||
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", |
||||
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" |
||||
], |
||||
"version": "==2018.4.16" |
||||
}, |
||||
"cffi": { |
||||
"hashes": [ |
||||
"sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743", |
||||
"sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef", |
||||
"sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50", |
||||
"sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f", |
||||
"sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93", |
||||
"sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257", |
||||
"sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3", |
||||
"sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc", |
||||
"sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04", |
||||
"sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6", |
||||
"sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359", |
||||
"sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596", |
||||
"sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b", |
||||
"sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd", |
||||
"sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95", |
||||
"sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e", |
||||
"sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6", |
||||
"sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca", |
||||
"sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31", |
||||
"sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1", |
||||
"sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085", |
||||
"sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801", |
||||
"sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4", |
||||
"sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184", |
||||
"sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917", |
||||
"sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f", |
||||
"sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb" |
||||
], |
||||
"version": "==1.11.5" |
||||
}, |
||||
"chardet": { |
||||
"hashes": [ |
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", |
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" |
||||
], |
||||
"version": "==3.0.4" |
||||
}, |
||||
"coincurve": { |
||||
"hashes": [ |
||||
"sha256:14f775b2a2034661ba125655529c883ba09936d16edd2edd28714d9be6ed7ca8", |
||||
"sha256:23bb379ab641423aea822effc3c63f06893f126cfd877e310382549048b6c4a6", |
||||
"sha256:29252b639e4c86d258cd01f747a8a00bc3e0533606e04cd1716af4b27cdcfe35", |
||||
"sha256:59bf263ce47e25865ea3491fa4d2d075ca3feb77d5ba961e95124d20b97916f8", |
||||
"sha256:605e73623f3b4d7a041af8032d55902fbb6b36151db427bad1655493a9bafcb3", |
||||
"sha256:683efd4f0ee89fa15ce7d6c4bb0cb48c86178f66a5d8538698ffdad8a079df3a", |
||||
"sha256:76b8c2738c9535223248c8da2b71de791b50ef18b6b8f1cd11b16242af9096b2", |
||||
"sha256:7afa48c11124b1d14baf63ef543e3438af0d8ba82b580f7a3b0c82b1fae2c697", |
||||
"sha256:7d66d081f46ce0e2c63d55cc791e7c1e6b0115eaee3c965edc0fb4f93d541537", |
||||
"sha256:7eaaa1d73084ed3436d64096dd8a22fd76a58f3cdbf5e3e3b949e73e694e17b6", |
||||
"sha256:9f565ca651e4304387460d8230cd8cc23ccea97c4a03f260b6b6238728516122", |
||||
"sha256:ad41b88ceffb953f4abc8c2b09123aeb4ba2f6949301ba1a8908832415f38255", |
||||
"sha256:ca8008b6c32726f15a50c3e9bac81c22d370b466377b21a8104e263610e90d94", |
||||
"sha256:ed671ecef3eb69aa46f1805d136b793a627fce94fc90d20f86ac5a357e00c08f" |
||||
], |
||||
"version": "==7.1.0" |
||||
}, |
||||
"coverage": { |
||||
"hashes": [ |
||||
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", |
||||
"sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", |
||||
"sha256:104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a", |
||||
"sha256:15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd", |
||||
"sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", |
||||
"sha256:1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2", |
||||
"sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", |
||||
"sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", |
||||
"sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", |
||||
"sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", |
||||
"sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", |
||||
"sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", |
||||
"sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", |
||||
"sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", |
||||
"sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", |
||||
"sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", |
||||
"sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", |
||||
"sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", |
||||
"sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", |
||||
"sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", |
||||
"sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", |
||||
"sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", |
||||
"sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", |
||||
"sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", |
||||
"sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", |
||||
"sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", |
||||
"sha256:9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4", |
||||
"sha256:ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91", |
||||
"sha256:b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d", |
||||
"sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", |
||||
"sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", |
||||
"sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", |
||||
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", |
||||
"sha256:e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77", |
||||
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80", |
||||
"sha256:f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==4.5.1" |
||||
}, |
||||
"cytoolz": { |
||||
"hashes": [ |
||||
"sha256:84cc06fa40aa310f2df79dd440fc5f84c3e20f01f9f7783fc9c38d0a11ba00e5" |
||||
], |
||||
"version": "==0.9.0.1" |
||||
}, |
||||
"dictionaries": { |
||||
"hashes": [ |
||||
"sha256:1ec6d4b2e2c5762a7423f66a3b423bc976439137e1537df5a164ea040abca2cb", |
||||
"sha256:26e0c57694d5e01b648c058939d69fbdc6d0caf04cd5b70cb7b4a69e577c1c31" |
||||
], |
||||
"version": "==0.0.1" |
||||
}, |
||||
"eth-abi": { |
||||
"hashes": [ |
||||
"sha256:3b965a707640cac5260208ceb58e02fd41b58b8e356dc95784dfdef8e3b1d4d0", |
||||
"sha256:58aed210e49da6bd318c026d306da2bf4c63022745460a791546ac10c4982162" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==1.0.0" |
||||
}, |
||||
"eth-account": { |
||||
"hashes": [ |
||||
"sha256:8c33e63e1e04527a37e00616569313e009db1efc5619731f3d4ec8890eea5ca4", |
||||
"sha256:c386f0e3e2e3b56c6f564fa4001a05d5dca5844e69794750e8a7621083308941" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==0.2.0" |
||||
}, |
||||
"eth-hash": { |
||||
"hashes": [ |
||||
"sha256:43adcab75a957fcf8c453d5542be55e4e0bd4e166270f45b09ac69b4d6486a06", |
||||
"sha256:8695f5f3794497d1357b2ef6e84c67a7daf4bfec1dde9f76ff6b2022c2cc03a6" |
||||
], |
||||
"version": "==0.1.2" |
||||
}, |
||||
"eth-keyfile": { |
||||
"hashes": [ |
||||
"sha256:70d734af17efdf929a90bb95375f43522be4ed80c3b9e0a8bca575fb11cd1159", |
||||
"sha256:939540efb503380bc30d926833e6a12b22c6750de80feef3720d79e5a79de47d" |
||||
], |
||||
"version": "==0.5.1" |
||||
}, |
||||
"eth-keys": { |
||||
"hashes": [ |
||||
"sha256:5ab2612f457452dc0a318655051cdd05c20f4db2f445003a46c98d324101b0e4", |
||||
"sha256:b48fc92a527bd905525855ebe45e79ba17be6654c4bedb947119648c145c74c0" |
||||
], |
||||
"version": "==0.2.0b3" |
||||
}, |
||||
"eth-rlp": { |
||||
"hashes": [ |
||||
"sha256:1330ebf341cd13fefbd9edaa038054cb19bc38368f866eb777f1f880577ed499", |
||||
"sha256:773bd96b4b83939822ef5d7dffa90448d5ccc2d38e5aeb03850c808ae43c183d" |
||||
], |
||||
"version": "==0.1.0" |
||||
}, |
||||
"eth-tester": { |
||||
"hashes": [ |
||||
"sha256:2e85782fc0627c5f29ed143865b8c3f27411bc28c78d6273ea797a24527e265c", |
||||
"sha256:836695b7c3159c9d9461de3397c5e1b044d798e785181c3de2012ad04be0a2f6" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==0.1.0b23" |
||||
}, |
||||
"eth-utils": { |
||||
"hashes": [ |
||||
"sha256:0eb71bdafda7e7e4c80ba98c06b3f89472e8ba0183a149be678f13cbb3b2e9b4", |
||||
"sha256:add4cc71b64e40b15c1e7b037905daf59da58e046004bde7a2915f86a7fc8e57" |
||||
], |
||||
"version": "==1.0.3" |
||||
}, |
||||
"ethereum": { |
||||
"hashes": [ |
||||
"sha256:69a22c2f793970d184777bb92589e67d0f622d56eda7c3c1bfc1f0edad522c1c" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==2.3.1" |
||||
}, |
||||
"future": { |
||||
"hashes": [ |
||||
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb" |
||||
], |
||||
"version": "==0.16.0" |
||||
}, |
||||
"hexbytes": { |
||||
"hashes": [ |
||||
"sha256:27cc227ae95fc20d44325ac0329a0293d656a05230da079650705030c7d7a819", |
||||
"sha256:67e5608cb4a14d0a4ced058e595bb1f70c207ef2b5219fdc82af10e54bcf38de" |
||||
], |
||||
"version": "==0.1.0" |
||||
}, |
||||
"idna": { |
||||
"hashes": [ |
||||
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f", |
||||
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4" |
||||
], |
||||
"version": "==2.6" |
||||
}, |
||||
"jinja2": { |
||||
"hashes": [ |
||||
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", |
||||
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==2.10" |
||||
}, |
||||
"laser-ethereum": { |
||||
"hashes": [ |
||||
"sha256:720b35d554c7dbd160bfc8f8de630e8b856fec34950a89844eb340bdcd052338" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==0.16.0" |
||||
}, |
||||
"markupsafe": { |
||||
"hashes": [ |
||||
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" |
||||
], |
||||
"version": "==1.0" |
||||
}, |
||||
"pbkdf2": { |
||||
"hashes": [ |
||||
"sha256:ac6397369f128212c43064a2b4878038dab78dab41875364554aaf2a684e6979" |
||||
], |
||||
"version": "==1.3" |
||||
}, |
||||
"persistent": { |
||||
"hashes": [ |
||||
"sha256:1d01c21746a5583c025800a312815c61ca1010a4b39f2b5e072f5b8edbee27df", |
||||
"sha256:26060716176a6fe0e1459f06c7d165950a0caca9793b2a511ad6b054d7d154ff", |
||||
"sha256:2890566acc8dd8e08407e119ea926fa41ca71f3fe83918303bc86f895e588f65", |
||||
"sha256:2d5e67ee369610f3198b566b3bae22436248bc42d51d3e283662b60defe568f2", |
||||
"sha256:3190e88b9717e8368e4f6b82a706cdb475ebbdc499023c9a0f1967de4e08f902", |
||||
"sha256:46d62295a2ee2ed3eefccef5d47d21fc616a6c1113ee1f6063c9b8061abb84d0", |
||||
"sha256:4766d57e225b5b6c2a120c80de2e383dec05daaf0406ceb8cde0cc94524e6eae", |
||||
"sha256:4a6b9c1ee2bb220197be8847f331d714a5a0ad63ce5b86cb29bc7fa77d7e7a41", |
||||
"sha256:4eb5be9f1318883ab71110a3c1844a08d5bbdf52428f2c7dec382ae83938d90c", |
||||
"sha256:52c751883ab367b4b150a3ec7b85847c18f9d0b64891b7426e851d3b46f1bbe0", |
||||
"sha256:56a1f80dd89cfd0e9cf90cf8034653a218ae996f09f9c23ad0050aafb45dde7c", |
||||
"sha256:59a9f2b3baab9bfc4780325b01f4136064411f008b07bfdc9a5100c7cd6c1404", |
||||
"sha256:7fe9f29b3cdeb528013692870f94d89bf2a6492a78ba07a0cda204f1fd133b7b", |
||||
"sha256:864113a235652a01f5c453ace560683688539a50706c6cfac920d610658794dc", |
||||
"sha256:8aed3d08a9f4935fbf46d50cc6865cec0075040b53df2d2a76f5f9512c8bb05f", |
||||
"sha256:90afcfa3b2d1f91635fcb161091f509fb345237dae6cdc98f8215e829d1c932f", |
||||
"sha256:994be774f65669ebea6429017aeea0e98627a2b830745378e160d3320873c226", |
||||
"sha256:9dff9299be1e486ab4cb89a6eddb07d0fb6176be230a6b62094acf1e40f0cd19", |
||||
"sha256:a55bfeb2977364efee0687f3b7b9d3ec83c2fe65018e26938ed0386717d47bc1", |
||||
"sha256:a5f70dffa8d252ac2f0cc7c5b86f4db32bedeee8c413b9e2289921d103217370", |
||||
"sha256:b4b8d1e6e9eb68360b244cdaffa916aa60fde2b7881f9268adc7118291f77443", |
||||
"sha256:bd05ab36bbffe099819135bbe8dd8b7da9f8eddbd2be50ee0250c504b8522604", |
||||
"sha256:cc61af5e11ad4516773f6791ba8cee5c1085c2fd58b1d5d7ef54250fc46dc396", |
||||
"sha256:cf264cd55866c7ffbcbe1328f8d8b28fd042a5dd0c03a03f68c0887df3aa1964", |
||||
"sha256:d77a0c6139b3fcd32c684e1a23666c5076ea9fcf4c2eecc564b98d5254d930e0", |
||||
"sha256:e91af0b256b9f593c28f95ad2422757c170120734aafbfda2402242ee120c18c", |
||||
"sha256:ef28d3874e076cad9e1392ca33e1320da21dcfa33d6dfae804324fbb5c656724", |
||||
"sha256:f1d3a571128391baacb844725dd7a7d355fdbf556434fc1a1b00b8edfc12bf50" |
||||
], |
||||
"version": "==4.2.4.2" |
||||
}, |
||||
"plyvel": { |
||||
"hashes": [ |
||||
"sha256:059d5689ffe078061edfb12fe9251abcac9996aa20cfec9049fdd7391c8ed742", |
||||
"sha256:134e78519403a6f71f1e66df945763413c48d0f6dec02e1a61f55adf0f83106d", |
||||
"sha256:368eb22344cfe0e5c4ab64b7ec970c02b3c99150cb595bd7e15a66287cd0dd11", |
||||
"sha256:a2f2ac289893fb7b43108528e557ce4c079e938883a1db12279e02b3e47eaa4f", |
||||
"sha256:adc2573a82d100db3d583da5348e74833cd47d4221cff299285d2c8e09570edf", |
||||
"sha256:b7736bf08e83c1a95cce0cb91809f94eb612666158feaba8c4b7ef2d3f955a6e" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==1.0.4" |
||||
}, |
||||
"py-ecc": { |
||||
"hashes": [ |
||||
"sha256:c7808a70c08bfc5c07b328f4df4406cfd3e365dd81f63bdd997c3c1eae34334a", |
||||
"sha256:f747ea69d40160c0a158c116bc3656eece9457cec446c8bfaffffd62f835de56" |
||||
], |
||||
"version": "==1.4.2" |
||||
}, |
||||
"py-flags": { |
||||
"hashes": [ |
||||
"sha256:2b2b18caa7f11bdb276029fac823a9102057a0953c58f618b8b7000ef3773836", |
||||
"sha256:87b2a3f9a86fc1f739753b11c359145024a65ad7392c3eb364794149acc78120" |
||||
], |
||||
"version": "==1.1.2" |
||||
}, |
||||
"py-solc": { |
||||
"hashes": [ |
||||
"sha256:0e657cc639b91649084901c00f0b14b921d40ab1b2faed0fb1216e80999bda72", |
||||
"sha256:90b7308abe35825979a1a03294bc383b5282bebdf9db1dda58223142dc7e9955" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==2.1.0" |
||||
}, |
||||
"pycparser": { |
||||
"hashes": [ |
||||
"sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226" |
||||
], |
||||
"version": "==2.18" |
||||
}, |
||||
"pycryptodome": { |
||||
"hashes": [ |
||||
"sha256:043c82cd3dd3120286a1b325ace93000cf52abb13a067c3ecb6220f874fe4c30", |
||||
"sha256:0cdd73492859d853f60b8185715312dbca465879661e28d354d1cf5ea11860e7", |
||||
"sha256:15013007e393d0cc0e69f4329a47c4c8597b7f3d02c12c03f805405542f70c71", |
||||
"sha256:19d81b92bff837cdade735b9023808556bb4868e1ce194dad4d5ec4e2b2851f3", |
||||
"sha256:1ceb3e87605c4f0080115a8a00abf45f5df27b0166a37fd669fbff4523273cfc", |
||||
"sha256:2354a77051ed4a2959ce2aac508071eb3e42fc348ea39228b2eac335990bf508", |
||||
"sha256:27bd2878200690b050dca34f505b5c623532324b3de40267c1484784063134df", |
||||
"sha256:322f239e51fda80233762400a8975ab728639b571fa58545b95b9c44042af010", |
||||
"sha256:49a71eb990af30ff6276cfe201eb83ed3640ae989c1b5973f7b55a46c94232d1", |
||||
"sha256:4b5a2680008da3ac0cef2d3661597e0cbf8a3eb19eed35b859fd67e2de63eb85", |
||||
"sha256:6d34fe5134eb5d62368e21e6f203ac1770bc7273e9536c4a280121312c2de53a", |
||||
"sha256:733d5eb7e5ceed8b9d0b3c24c81f52c04cb5de6786461388204fceefe4456aa5", |
||||
"sha256:7c73d3798fe2946953768b788ce554c0d4b390780f5e73d63bd833241af27bfe", |
||||
"sha256:97af76f5200f15e97cac58d77f319dec40b4bada98de697c91a9517e63b41d1a", |
||||
"sha256:97cc46ff02b99dafdc2e0385b325cec0f8a15bf8b285d6ed1d7e4a3bc2067ce1", |
||||
"sha256:a561b59e0c3548eb649af381b7c38c6fd8392bbd4d0a8214794b2b761f405af4", |
||||
"sha256:ab2c633bfc23cf41be9281228517cb6f87879f4f1aeb154ed72bd53ab7cc83e9", |
||||
"sha256:adb54316998337f315520bbd8ef4d8bbd940b4ddfaef8ba1db3c137c5e499399", |
||||
"sha256:b4a3b710287eb1fc3e2cc1af018063f003530dff00c9ea4c55ae19bc1f3923cc", |
||||
"sha256:bcfdb66d6604882c3f96eea922552c2487cc0aec4b883cd217b9d341d2f8fad0", |
||||
"sha256:c08c053eb8716bbbd5e13e38f453b9e46a063e68df8659f3c421dcb7519fd381", |
||||
"sha256:e51da4ef9d9e2695a04044152f380c2db17adc9fc6fad8e24d863ead9cd548ed", |
||||
"sha256:e850e07f54dc3de9a1efdd59d227fcd1cb30cdd307dafdc647c79e8f30cf5032", |
||||
"sha256:ebc579c41fe26748dc1bad4f9105f08740ee28826293a28103b3875968695a5e", |
||||
"sha256:ed94cb1b4bf24be734f2bf2db3e8ea75f3914d2f8e684291bee54bbe4a5a9151", |
||||
"sha256:f5e19802295e63bdf83bb92849285c01f7167840efb1c1e08507a50b10ba7efa", |
||||
"sha256:fc569682f012b1f62f8d28d8f9bc71f1de67648cd1bc124ef8ccf8db4edfc28a" |
||||
], |
||||
"version": "==3.6.1" |
||||
}, |
||||
"pyethash": { |
||||
"hashes": [ |
||||
"sha256:ff66319ce26b9d77df1f610942634dac9742e216f2c27b051c0a2c2dec9c2818" |
||||
], |
||||
"version": "==0.1.27" |
||||
}, |
||||
"pysha3": { |
||||
"hashes": [ |
||||
"sha256:0060a66be16665d90c432f55a0ba1f6480590cfb7d2ad389e688a399183474f0", |
||||
"sha256:11a2ba7a2e1d9669d0052fc8fb30f5661caed5512586ecbeeaf6bf9478ab5c48", |
||||
"sha256:386998ee83e313b6911327174e088021f9f2061cbfa1651b97629b761e9ef5c4", |
||||
"sha256:41be70b06c8775a9e4d4eeb52f2f6a3f356f17539a54eac61f43a29e42fd453d", |
||||
"sha256:4416f16b0f1605c25f627966f76873e432971824778b369bd9ce1bb63d6566d9", |
||||
"sha256:571a246308a7b63f15f5aa9651f99cf30f2a6acba18eddf28f1510935968b603", |
||||
"sha256:59111c08b8f34495575d12e5f2ce3bafb98bea470bc81e70c8b6df99aef0dd2f", |
||||
"sha256:5ec8da7c5c70a53b5fa99094af3ba8d343955b212bc346a0d25f6ff75853999f", |
||||
"sha256:684cb01d87ed6ff466c135f1c83e7e4042d0fc668fa20619f581e6add1d38d77", |
||||
"sha256:68c3a60a39f9179b263d29e221c1bd6e01353178b14323c39cc70593c30f21c5", |
||||
"sha256:6e6a84efb7856f5d760ee55cd2b446972cb7b835676065f6c4f694913ea8f8d9", |
||||
"sha256:827b308dc025efe9b6b7bae36c2e09ed0118a81f792d888548188e97b9bf9a3d", |
||||
"sha256:93abd775dac570cb9951c4e423bcb2bc6303a9d1dc0dc2b7afa2dd401d195b24", |
||||
"sha256:9c778fa8b161dc9348dc5cc361e94d54aa5ff18413788f4641f6600d4893a608", |
||||
"sha256:9fdd28884c5d0b4edfed269b12badfa07f1c89dbc5c9c66dd279833894a9896b", |
||||
"sha256:c7c2adcc43836223680ebdf91f1d3373543dc32747c182c8ca2e02d1b69ce030", |
||||
"sha256:c93a2676e6588abcfaecb73eb14485c81c63b94fca2000a811a7b4fb5937b8e8", |
||||
"sha256:cd5c961b603bd2e6c2b5ef9976f3238a561c58569945d4165efb9b9383b050ef", |
||||
"sha256:f9046d59b3e72aa84f6dae83a040bd1184ebd7fef4e822d38186a8158c89e3cf", |
||||
"sha256:fd7e66999060d079e9c0e8893e78d8017dad4f59721f6fe0be6307cd32127a07", |
||||
"sha256:fe988e73f2ce6d947220624f04d467faf05f1bbdbc64b0a201296bb3af92739e" |
||||
], |
||||
"version": "==1.0.2" |
||||
}, |
||||
"pyyaml": { |
||||
"hashes": [ |
||||
"sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", |
||||
"sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", |
||||
"sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", |
||||
"sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", |
||||
"sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", |
||||
"sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", |
||||
"sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7", |
||||
"sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", |
||||
"sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", |
||||
"sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", |
||||
"sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", |
||||
"sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", |
||||
"sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", |
||||
"sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269" |
||||
], |
||||
"version": "==3.12" |
||||
}, |
||||
"repoze.lru": { |
||||
"hashes": [ |
||||
"sha256:0429a75e19380e4ed50c0694e26ac8819b4ea7851ee1fc7583c8572db80aff77", |
||||
"sha256:f77bf0e1096ea445beadd35f3479c5cff2aa1efe604a133e67150bc8630a62ea" |
||||
], |
||||
"version": "==0.7" |
||||
}, |
||||
"requests": { |
||||
"hashes": [ |
||||
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", |
||||
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==2.18.4" |
||||
}, |
||||
"rlp": { |
||||
"hashes": [ |
||||
"sha256:87879a0ba1479b760cee98af165de2eee95258b261faa293199f60742be96f34" |
||||
], |
||||
"version": "==0.6.0" |
||||
}, |
||||
"scrypt": { |
||||
"hashes": [ |
||||
"sha256:18ccbc63d87c6f89b753194194bb37aeaf1abc517e4b989461d115c1d93ce128", |
||||
"sha256:232acdbc3434d2de55def8d5dbf1bc4b9bfc50da7c5741df2a6eebc4e18d3720", |
||||
"sha256:475ac80239b3d788ae71a09c3019ca915e149aaa339adcdd1c9eef121293dc88", |
||||
"sha256:4ad7188f2e42dbee2ff1cd72e3da40b170ba41847effbf0d726444f62ae60f3a", |
||||
"sha256:85919f023148cd9fb01d75ad4e3e061928c298fa6249a0cd6cd469c4b947595e", |
||||
"sha256:971db040d3963ebe4b919a203fe10d7d6659951d3644066314330983dc175ed4", |
||||
"sha256:a124719c686f2b5957e392465147fb3fd6077e7c643e9538cab1ee631eb01dde", |
||||
"sha256:a343c302b3e99dcb7fcbe57aa7919ed761f1568f854291ccebe1b5e6e2c9e509", |
||||
"sha256:bc131f74a688fa09993c518ca666a2ebd4268b207e039cbab03a034228140d3e", |
||||
"sha256:c23daecee405cb036845917295c76f8d747fc890158df40cb304b4b3c3640079", |
||||
"sha256:dc40f0e1a357a49ca62f30f2fc09e92e02c062a656f27949b436b2ba8002d9e1", |
||||
"sha256:f8239b2d47fa1d40bc27efd231dc7083695d10c1c2ac51a99380360741e0362d" |
||||
], |
||||
"version": "==0.8.6" |
||||
}, |
||||
"semantic-version": { |
||||
"hashes": [ |
||||
"sha256:2a4328680073e9b243667b201119772aefc5fc63ae32398d6afafff07c4f54c0", |
||||
"sha256:2d06ab7372034bcb8b54f2205370f4aa0643c133b7e6dbd129c5200b83ab394b" |
||||
], |
||||
"version": "==2.6.0" |
||||
}, |
||||
"six": { |
||||
"hashes": [ |
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", |
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" |
||||
], |
||||
"version": "==1.11.0" |
||||
}, |
||||
"toolz": { |
||||
"hashes": [ |
||||
"sha256:929f0a7ea7f61c178bd951bdae93920515d3fbdbafc8e6caf82d752b9b3b31c9" |
||||
], |
||||
"version": "==0.9.0" |
||||
}, |
||||
"transaction": { |
||||
"hashes": [ |
||||
"sha256:269601a3493cd3eddeb869419ceadfc5e6d2bc931e9970d11fc4649dab189c3c", |
||||
"sha256:9de0f93f833713270fbceaf6092194313c1de0afb660e66dea8e089855eb281c", |
||||
"sha256:f2242070e437e5d555ea3df809cb517860513254c828f33847df1c5e4b776c7a" |
||||
], |
||||
"version": "==2.2.1" |
||||
}, |
||||
"urllib3": { |
||||
"hashes": [ |
||||
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", |
||||
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" |
||||
], |
||||
"version": "==1.22" |
||||
}, |
||||
"z3-solver": { |
||||
"hashes": [ |
||||
"sha256:6b10b317f056890a341304071fb3ab220f0adb2c87439a04eba9e69028a7e3ff", |
||||
"sha256:c185d05d236c6c9756e914756c73f797cb618d81b42e694166639cce5bcfdb1f", |
||||
"sha256:c802dbe5368743dd30dd2a684c15b83b17c3c95df54b66f97611a5988ae0f696", |
||||
"sha256:e41001b7f43ecb9eb9bedf6762bd0e002561590487cc78c0b48f608a85ce02ac" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==4.5.1.0.post2" |
||||
}, |
||||
"zc.lockfile": { |
||||
"hashes": [ |
||||
"sha256:96cb13769e042988ea25d23d44cf09342ea0f887083d0f9736968f3617665853" |
||||
], |
||||
"version": "==1.3.0" |
||||
}, |
||||
"zconfig": { |
||||
"hashes": [ |
||||
"sha256:6c77f5658101ccd76f01592baa5dac563da36034a55d02d8ef616e690729c05d", |
||||
"sha256:de0a802e5dfea3c0b3497ccdbe33a5023c4265f950f33e35dd4cf078d2a81b19" |
||||
], |
||||
"version": "==3.2.0" |
||||
}, |
||||
"zodb": { |
||||
"hashes": [ |
||||
"sha256:0b306042f4f0d558a477d65c34b0dd6e7604c6e583f55dfda52befa2fa13e076" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==5.4.0" |
||||
}, |
||||
"zodbpickle": { |
||||
"hashes": [ |
||||
"sha256:04e6eca53b6e7f562ff7c53415fbdf277166f89f254b5d341db1bcc1f7f0b770", |
||||
"sha256:0a9788a37979715cfa98052e37d6ee1880463aa0fba635caf2ec64b6fdbd2e4a", |
||||
"sha256:1397a43cf7ad7f5c9b75cf30df9232b0f03a4d74154ee344afc5e09331a3b3a1", |
||||
"sha256:1f93b692fcc4dfa20a06e40f4b24e587fb0dd9c00834fac295ee73e1c2623090", |
||||
"sha256:2261f0f4958c48ba81e30e144f5a0ac937452200c2bf375489c38f0343f45902", |
||||
"sha256:23228cf8c33c6955ab215324c84688e82848c2669a06e1b1656b4facfff81fe0", |
||||
"sha256:33e6066759f4c462baf3a65e41095c0d93751f2817d19874405d3b2094ff9108", |
||||
"sha256:3af9169fb1d5901cf6693ab356b0dfda20ad2cacc5673fad59b4449ed50d5399", |
||||
"sha256:4ce6982ec92a85dd0af89671bf0252a7f7259f762d9fd5ec4bec0049309129a2", |
||||
"sha256:60bf75ac7efa1ab6d72b5460e86cb69979599f828f60175c1a8f05dda0e6184a", |
||||
"sha256:87c23cba15329957ff867471b8eef9c0b2174c40f61a6978d20a71f4c524d875", |
||||
"sha256:87f0467e944101a7dcd674b43a33a10d4f58b61fffcb9ac0efd2453726fd0309", |
||||
"sha256:8f22db458f3b682b1ed4a89e4f825cadbc278ce89b0915ed25d05b841630c86d", |
||||
"sha256:95fbaac0639f1d29008d09fd5eb421a8dbc87e5e4e282729772250866a028c52", |
||||
"sha256:96dce0fb50d4f9ae64fe289826904ea851fd7f5d30597296ca5fb0a69396c0be", |
||||
"sha256:9fb4630ac7893fc97f69c8069577d90a84974f96d2dcdb2c067c0698f232c02d", |
||||
"sha256:a31b82d1df4f34587f4c4be22165be00f0ec04e8818d8806169f28c0fd1adf11", |
||||
"sha256:abc02cb2adbdad9c64f03b9e3195cb118a3a2239139757dbb88d5693cd113d54", |
||||
"sha256:bcf7ecef9a5966facc3a3823ce2ca022d6289b3646860fc47260e55038e9d321", |
||||
"sha256:c259e38812691512a0b11d96ffc81e9ad3c78cbb9e37d2faf19ad5ce18870e4b", |
||||
"sha256:e781b3b33aef6e667725fcf4365d4422248e8eae9ea394006ace9d65e2c99ff8", |
||||
"sha256:efdd2589aab15cbed8bbe8958552dc9a2ceeb178d138217bfa6db6012847b4ed", |
||||
"sha256:f14109e4c3c5353cc1926e4a0b7a9fda74731e2ea98320701ab69e0b9787a424" |
||||
], |
||||
"version": "==1.0" |
||||
}, |
||||
"zope.interface": { |
||||
"hashes": [ |
||||
"sha256:21506674d30c009271fe68a242d330c83b1b9d76d62d03d87e1e9528c61beea6", |
||||
"sha256:3d184aff0756c44fff7de69eb4cd5b5311b6f452d4de28cb08343b3f21993763", |
||||
"sha256:467d364b24cb398f76ad5e90398d71b9325eb4232be9e8a50d6a3b3c7a1c8789", |
||||
"sha256:57c38470d9f57e37afb460c399eb254e7193ac7fb8042bd09bdc001981a9c74c", |
||||
"sha256:9ada83f4384bbb12dedc152bcdd46a3ac9f5f7720d43ac3ce3e8e8b91d733c10", |
||||
"sha256:a1daf9c5120f3cc6f2b5fef8e1d2a3fb7bbbb20ed4bfdc25bc8364bc62dcf54b", |
||||
"sha256:e6b77ae84f2b8502d99a7855fa33334a1eb6159de45626905cb3e454c023f339", |
||||
"sha256:e881ef610ff48aece2f4ee2af03d2db1a146dc7c705561bd6089b2356f61641f", |
||||
"sha256:f41037260deaacb875db250021fe883bf536bf6414a4fd25b25059b02e31b120" |
||||
], |
||||
"version": "==4.5.0" |
||||
} |
||||
}, |
||||
"develop": { |
||||
"astroid": { |
||||
"hashes": [ |
||||
"sha256:35cfae47aac19c7b407b7095410e895e836f2285ccf1220336afba744cc4c5f2", |
||||
"sha256:38186e481b65877fd8b1f9acc33e922109e983eb7b6e487bd4c71002134ad331" |
||||
], |
||||
"version": "==1.6.3" |
||||
}, |
||||
"attrs": { |
||||
"hashes": [ |
||||
"sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9", |
||||
"sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==17.4.0" |
||||
}, |
||||
"isort": { |
||||
"hashes": [ |
||||
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af", |
||||
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8", |
||||
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497" |
||||
], |
||||
"version": "==4.3.4" |
||||
}, |
||||
"lazy-object-proxy": { |
||||
"hashes": [ |
||||
"sha256:0ce34342b419bd8f018e6666bfef729aec3edf62345a53b537a4dcc115746a33", |
||||
"sha256:1b668120716eb7ee21d8a38815e5eb3bb8211117d9a90b0f8e21722c0758cc39", |
||||
"sha256:209615b0fe4624d79e50220ce3310ca1a9445fd8e6d3572a896e7f9146bbf019", |
||||
"sha256:27bf62cb2b1a2068d443ff7097ee33393f8483b570b475db8ebf7e1cba64f088", |
||||
"sha256:27ea6fd1c02dcc78172a82fc37fcc0992a94e4cecf53cb6d73f11749825bd98b", |
||||
"sha256:2c1b21b44ac9beb0fc848d3993924147ba45c4ebc24be19825e57aabbe74a99e", |
||||
"sha256:2df72ab12046a3496a92476020a1a0abf78b2a7db9ff4dc2036b8dd980203ae6", |
||||
"sha256:320ffd3de9699d3892048baee45ebfbbf9388a7d65d832d7e580243ade426d2b", |
||||
"sha256:50e3b9a464d5d08cc5227413db0d1c4707b6172e4d4d915c1c70e4de0bbff1f5", |
||||
"sha256:5276db7ff62bb7b52f77f1f51ed58850e315154249aceb42e7f4c611f0f847ff", |
||||
"sha256:61a6cf00dcb1a7f0c773ed4acc509cb636af2d6337a08f362413c76b2b47a8dd", |
||||
"sha256:6ae6c4cb59f199d8827c5a07546b2ab7e85d262acaccaacd49b62f53f7c456f7", |
||||
"sha256:7661d401d60d8bf15bb5da39e4dd72f5d764c5aff5a86ef52a042506e3e970ff", |
||||
"sha256:7bd527f36a605c914efca5d3d014170b2cb184723e423d26b1fb2fd9108e264d", |
||||
"sha256:7cb54db3535c8686ea12e9535eb087d32421184eacc6939ef15ef50f83a5e7e2", |
||||
"sha256:7f3a2d740291f7f2c111d86a1c4851b70fb000a6c8883a59660d95ad57b9df35", |
||||
"sha256:81304b7d8e9c824d058087dcb89144842c8e0dea6d281c031f59f0acf66963d4", |
||||
"sha256:933947e8b4fbe617a51528b09851685138b49d511af0b6c0da2539115d6d4514", |
||||
"sha256:94223d7f060301b3a8c09c9b3bc3294b56b2188e7d8179c762a1cda72c979252", |
||||
"sha256:ab3ca49afcb47058393b0122428358d2fbe0408cf99f1b58b295cfeb4ed39109", |
||||
"sha256:bd6292f565ca46dee4e737ebcc20742e3b5be2b01556dafe169f6c65d088875f", |
||||
"sha256:cb924aa3e4a3fb644d0c463cad5bc2572649a6a3f68a7f8e4fbe44aaa6d77e4c", |
||||
"sha256:d0fc7a286feac9077ec52a927fc9fe8fe2fabab95426722be4c953c9a8bede92", |
||||
"sha256:ddc34786490a6e4ec0a855d401034cbd1242ef186c20d79d2166d6a4bd449577", |
||||
"sha256:e34b155e36fa9da7e1b7c738ed7767fc9491a62ec6af70fe9da4a057759edc2d", |
||||
"sha256:e5b9e8f6bda48460b7b143c3821b21b452cb3a835e6bbd5dd33aa0c8d3f5137d", |
||||
"sha256:e81ebf6c5ee9684be8f2c87563880f93eedd56dd2b6146d8a725b50b7e5adb0f", |
||||
"sha256:eb91be369f945f10d3a49f5f9be8b3d0b93a4c2be8f8a5b83b0571b8123e0a7a", |
||||
"sha256:f460d1ceb0e4a5dcb2a652db0904224f367c9b3c1470d5a7683c0480e582468b" |
||||
], |
||||
"version": "==1.3.1" |
||||
}, |
||||
"mccabe": { |
||||
"hashes": [ |
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", |
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" |
||||
], |
||||
"version": "==0.6.1" |
||||
}, |
||||
"more-itertools": { |
||||
"hashes": [ |
||||
"sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea", |
||||
"sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e", |
||||
"sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44" |
||||
], |
||||
"version": "==4.1.0" |
||||
}, |
||||
"pluggy": { |
||||
"hashes": [ |
||||
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff", |
||||
"sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c", |
||||
"sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5" |
||||
], |
||||
"version": "==0.6.0" |
||||
}, |
||||
"py": { |
||||
"hashes": [ |
||||
"sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881", |
||||
"sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a" |
||||
], |
||||
"version": "==1.5.3" |
||||
}, |
||||
"pylint": { |
||||
"hashes": [ |
||||
"sha256:0b7e6b5d9f1d4e0b554b5d948f14ed7969e8cdf9a0120853e6e5af60813b18ab", |
||||
"sha256:34738a82ab33cbd3bb6cd4cef823dbcabdd2b6b48a4e3a3054a2bbbf0c712be9" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==1.8.4" |
||||
}, |
||||
"pytest": { |
||||
"hashes": [ |
||||
"sha256:6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c", |
||||
"sha256:fae491d1874f199537fd5872b5e1f0e74a009b979df9d53d1553fd03da1703e1" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==3.5.0" |
||||
}, |
||||
"six": { |
||||
"hashes": [ |
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", |
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" |
||||
], |
||||
"version": "==1.11.0" |
||||
}, |
||||
"wrapt": { |
||||
"hashes": [ |
||||
"sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6" |
||||
], |
||||
"version": "==1.10.11" |
||||
}, |
||||
"yapf": { |
||||
"hashes": [ |
||||
"sha256:7d8ae3567f3fb2d288f127d35e4decb3348c96cd091001e02e818465da618f90", |
||||
"sha256:dd23b52edbb4c0461d0383050f7886175b0df9ab8fd0b67edd41f94e25770993" |
||||
], |
||||
"index": "pypi", |
||||
"version": "==0.21.0" |
||||
} |
||||
} |
||||
} |
@ -1,12 +1,37 @@ |
||||
#!/bin/sh |
||||
|
||||
python3 --version |
||||
echo "Please make sure you are using python 3.6.x" |
||||
echo -n "Checking Python version... " |
||||
python -c 'import sys |
||||
print(sys.version) |
||||
assert sys.version_info[0:2] >= (3,6), \ |
||||
"""Please make sure you are using Python 3.6.x. |
||||
You ran with {}""".format(sys.version)' || exit $? |
||||
|
||||
solc --version |
||||
echo "Please make sure you are using solc 0.4.21" |
||||
echo "Checking solc version..." |
||||
out=$(solc --version) || { |
||||
echo 2>&1 "Please make sure you have solc installed, version 0.4.21 or greater" |
||||
|
||||
} |
||||
case $out in |
||||
*Version:\ 0.4.2[1-9]* ) |
||||
echo $out |
||||
break ;; |
||||
* ) |
||||
echo $out |
||||
echo "Please make sure your solc version is at least 0.4.21" |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
echo "Checking that truffle is installed..." |
||||
if ! which truffle ; then |
||||
echo "Please make sure you have etherum truffle installed (npm install -g truffle)" |
||||
exit 2 |
||||
fi |
||||
|
||||
rm -rf ./tests/testdata/outputs_current/ |
||||
mkdir -p ./tests/testdata/outputs_current/ |
||||
rm -rf ./tests/testdata/outputs_current_laser_result/ |
||||
mkdir -p ./tests/testdata/outputs_current_laser_result/ |
||||
mkdir -p /tmp/test-reports |
||||
pytest --junitxml=/tmp/test-reports/junit.xml |
||||
|
@ -0,0 +1,15 @@ |
||||
#!/bin/sh |
||||
set -eo pipefail |
||||
|
||||
NAME=mythril/myth |
||||
|
||||
VERSION_TAG=${NAME}:${CIRCLE_TAG#?} |
||||
LATEST_TAG=${NAME}:latest |
||||
|
||||
docker build -t ${VERSION_TAG} . |
||||
docker tag ${VERSION_TAG} ${LATEST_TAG} |
||||
|
||||
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD |
||||
|
||||
docker push ${VERSION_TAG} |
||||
docker push ${LATEST_TAG} |
@ -0,0 +1,59 @@ |
||||
from mythril.analysis.report import Issue |
||||
""" |
||||
MODULE DESCRIPTION: |
||||
|
||||
Check for multiple sends in a single transaction |
||||
""" |
||||
|
||||
|
||||
def execute(statespace): |
||||
issues = [] |
||||
|
||||
for call in statespace.calls: |
||||
findings = [] |
||||
# explore state |
||||
findings += _explore_states(call, statespace) |
||||
# explore nodes |
||||
findings += _explore_nodes(call, statespace) |
||||
|
||||
if len(findings) > 0: |
||||
node = call.node |
||||
instruction = call.state.get_current_instruction() |
||||
issue = Issue(node.contract_name, node.function_name, instruction['address'], |
||||
"Multiple Calls", |
||||
"Information") |
||||
|
||||
issue.description = \ |
||||
"Multiple sends exist in one transaction, try to isolate each external call into its own transaction." \ |
||||
" As external calls can fail accidentally or deliberately.\nConsecutive calls: \n" |
||||
|
||||
for finding in findings: |
||||
issue.description += \ |
||||
"Call at address: {}\n".format(finding.state.get_current_instruction()['address']) |
||||
|
||||
issues.append(issue) |
||||
return issues |
||||
|
||||
|
||||
def _explore_nodes(call, statespace): |
||||
children = _child_nodes(statespace, call.node) |
||||
sending_children = list(filter(lambda call: call.node in children, statespace.calls)) |
||||
return sending_children |
||||
|
||||
|
||||
def _explore_states(call, statespace): |
||||
other_calls = list( |
||||
filter(lambda other: other.node == call.node and other.state_index > call.state_index, statespace.calls) |
||||
) |
||||
return other_calls |
||||
|
||||
|
||||
def _child_nodes(statespace, node): |
||||
result = [] |
||||
children = [statespace.nodes[edge.node_to] for edge in statespace.edges if edge.node_from == node.uid] |
||||
|
||||
for child in children: |
||||
result.append(child) |
||||
result += _child_nodes(statespace, child) |
||||
|
||||
return result |
@ -0,0 +1,37 @@ |
||||
# Analysis results for {{ filename }} |
||||
{% if issues %} |
||||
{% for issue in issues %} |
||||
|
||||
## {{ issue.title }} |
||||
|
||||
- Type: {{ issue.type }} |
||||
- Contract: {{ issue.contract | default("Unknown") }} |
||||
- Function name: `{{ issue.function }}` |
||||
- PC address: {{ issue.address }} |
||||
|
||||
### Description |
||||
|
||||
{{ issue.description.rstrip() }} |
||||
{% if issue.filename and issue.lineno %} |
||||
In file: {{ issue.filename }}:{{ issue.lineno }} |
||||
{% endif %} |
||||
{% if issue.code %} |
||||
|
||||
### Code |
||||
|
||||
``` |
||||
{{ issue.code }} |
||||
``` |
||||
{% endif %} |
||||
{% if verbose and issue.debug %} |
||||
-------------------- |
||||
### Debugging Information: |
||||
|
||||
{{ issue.debug }} |
||||
|
||||
{% endif %} |
||||
{% endfor %} |
||||
{% else %} |
||||
|
||||
The analysis was completed successfully. No issues were detected. |
||||
{% endif %} |
@ -0,0 +1,29 @@ |
||||
{% if issues %} |
||||
{% for issue in issues %} |
||||
==== {{ issue.title }} ==== |
||||
Type: {{ issue.type }} |
||||
Contract: {{ issue.contract | default("Unknown") }} |
||||
Function name: {{ issue.function }} |
||||
PC address: {{ issue.address }} |
||||
{{ issue.description }} |
||||
-------------------- |
||||
{% if issue.filename and issue.lineno %} |
||||
In file: {{ issue.filename }}:{{ issue.lineno }} |
||||
{% endif %} |
||||
{% if issue.code %} |
||||
|
||||
{{ issue.code }} |
||||
|
||||
-------------------- |
||||
{% endif %} |
||||
{% if verbose and issue.debug %} |
||||
-------------------- |
||||
DEBUGGING INFORMATION: |
||||
|
||||
{{ issue.debug }} |
||||
{% endif %} |
||||
|
||||
{% endfor %} |
||||
{% else %} |
||||
The analysis was completed successfully. No issues were detected. |
||||
{% endif %} |
@ -1,157 +0,0 @@ |
||||
import os |
||||
import hashlib |
||||
import persistent.list |
||||
import transaction |
||||
from BTrees.OOBTree import BTree |
||||
import ZODB |
||||
from ZODB import FileStorage |
||||
from multiprocessing import Pool |
||||
import logging |
||||
from mythril.ether.ethcontract import ETHContract, InstanceList |
||||
from mythril import ether |
||||
import time |
||||
|
||||
BLOCKS_PER_THREAD = 256 |
||||
NUM_THREADS = 8 |
||||
|
||||
|
||||
def get_persistent_storage(db_dir=None): |
||||
if not db_dir: |
||||
db_dir = os.path.join(os.path.expanduser('~'), ".mythril") |
||||
|
||||
if not os.path.exists(db_dir): |
||||
os.makedirs(db_dir) |
||||
|
||||
db_path = os.path.join(db_dir, "contractstorage.fs") |
||||
|
||||
storage = FileStorage.FileStorage(db_path) |
||||
db = ZODB.DB(storage) |
||||
connection = db.open() |
||||
storage_root = connection.root() |
||||
|
||||
try: |
||||
contract_storage = storage_root['contractStorage'] |
||||
except KeyError: |
||||
contract_storage = ContractStorage() |
||||
storage_root['contractStorage'] = contract_storage |
||||
|
||||
return contract_storage, db |
||||
|
||||
class SyncBlocks(object): |
||||
''' |
||||
Processes the block chunk |
||||
''' |
||||
|
||||
def __init__(self, eth): |
||||
self.eth = eth |
||||
|
||||
def __call__(self, startblock): |
||||
''' |
||||
Processesing method |
||||
''' |
||||
logging.info("SYNC_BLOCKS %d to %d" % (startblock, startblock + BLOCKS_PER_THREAD)) |
||||
|
||||
contracts = {} |
||||
|
||||
for blockNum in range(startblock, startblock + BLOCKS_PER_THREAD): |
||||
block = self.eth.eth_getBlockByNumber(blockNum) |
||||
|
||||
for tx in block['transactions']: |
||||
|
||||
if not tx['to']: |
||||
|
||||
receipt = self.eth.eth_getTransactionReceipt(tx['hash']) |
||||
|
||||
if receipt is not None: |
||||
|
||||
contract_address = receipt['contractAddress'] |
||||
|
||||
contract_code = self.eth.eth_getCode(contract_address) |
||||
contract_balance = self.eth.eth_getBalance(contract_address) |
||||
|
||||
if not contract_balance: |
||||
continue |
||||
|
||||
ethcontract = ETHContract(contract_code, tx['input']) |
||||
|
||||
m = hashlib.md5() |
||||
m.update(contract_code.encode('UTF-8')) |
||||
contract_hash = m.digest() |
||||
|
||||
contracts[contract_hash] = {'ethcontract': ethcontract, 'address': contract_address, 'balance': contract_balance} |
||||
|
||||
blockNum -= 1 |
||||
|
||||
return contracts |
||||
|
||||
class ContractStorage(persistent.Persistent): |
||||
|
||||
def __init__(self): |
||||
self.contracts = BTree() |
||||
self.instance_lists = BTree() |
||||
self.last_block = 0 |
||||
self.eth = None |
||||
|
||||
def get_contract_by_hash(self, contract_hash): |
||||
return self.contracts[contract_hash] |
||||
|
||||
def initialize(self, eth): |
||||
|
||||
self.eth = eth |
||||
|
||||
if self.last_block: |
||||
blockNum = self.last_block |
||||
print("Resuming synchronization from block " + str(blockNum)) |
||||
else: |
||||
|
||||
blockNum = eth.eth_blockNumber() |
||||
print("Starting synchronization from latest block: " + str(blockNum)) |
||||
|
||||
processed = 0 |
||||
|
||||
while (blockNum > 0): |
||||
|
||||
numbers = [] |
||||
|
||||
for i in range(1, NUM_THREADS + 1): |
||||
numbers.append(max(0, blockNum - (i * BLOCKS_PER_THREAD))) |
||||
|
||||
pool = Pool(NUM_THREADS, initargs=(self.eth)) |
||||
results = pool.map(SyncBlocks(self.eth), numbers) |
||||
pool.close() |
||||
pool.join() |
||||
|
||||
for result in results: |
||||
for (contract_hash, data) in result.items(): |
||||
|
||||
try: |
||||
self.contracts[contract_hash] |
||||
except KeyError: |
||||
self.contracts[contract_hash] = data['ethcontract'] |
||||
m = InstanceList() |
||||
self.instance_lists[contract_hash] = m |
||||
|
||||
self.instance_lists[contract_hash].add(data['address'], data['balance']) |
||||
|
||||
blockNum -= NUM_THREADS * BLOCKS_PER_THREAD |
||||
processed += NUM_THREADS * BLOCKS_PER_THREAD |
||||
self.last_block = blockNum |
||||
transaction.commit() |
||||
|
||||
cost_time = time.time() - ether.start_time |
||||
print("%d blocks processed (in %d seconds), %d unique contracts in database, next block: %d" % (processed, cost_time, len(self.contracts), max(0, blockNum))) |
||||
|
||||
# If we've finished initializing the database, start over from the end of the chain if we want to initialize again |
||||
self.last_block = 0 |
||||
print("Finished synchronization") |
||||
|
||||
def search(self, expression, callback_func): |
||||
|
||||
all_keys = list(self.contracts) |
||||
|
||||
for k in all_keys: |
||||
|
||||
if self.contracts[k].matches_expression(expression): |
||||
m = self.instance_lists[k] |
||||
|
||||
callback_func(k.hex(), self.contracts[k], m.addresses, m.balances) |
@ -0,0 +1,74 @@ |
||||
gascost = { |
||||
'PUSH': 3, |
||||
'DUP': 3, |
||||
'SWAP': 3, |
||||
'STOP': 0, |
||||
'ADD': 3, |
||||
'MUL': 5, |
||||
'SUB': 3, |
||||
'DIV': 5, |
||||
'SDIV': 5, |
||||
'MOD': 5, |
||||
'SMOD': 5, |
||||
'ADDMOD': 8, |
||||
'MULMOD': 8, |
||||
'EXP': 10, |
||||
'SIGNEXTEND': 5, |
||||
'LT': 3, |
||||
'GT': 3, |
||||
'SLT': 3, |
||||
'SGT': 3, |
||||
'EQ': 3, |
||||
'ISZERO': 3, |
||||
'AND': 3, |
||||
'OR': 3, |
||||
'XOR': 3, |
||||
'NOT': 3, |
||||
'BYTE': 3, |
||||
'SHA3': 30, |
||||
'ADDRESS': 2, |
||||
'BALANCE': 400, |
||||
'ORIGIN': 2, |
||||
'CALLER': 2, |
||||
'CALLVALUE': 2, |
||||
'CALLDATALOAD': 3, |
||||
'CALLDATASIZE': 2, |
||||
'CALLDATACOPY': 3, |
||||
'CODESIZE': 2, |
||||
'CODECOPY': 3, |
||||
'GASPRICE': 2, |
||||
'EXTCODESIZE': 700, |
||||
'EXTCODECOPY': 700, |
||||
'BLOCKHASH': 20, |
||||
'COINBASE': 2, |
||||
'TIMESTAMP': 2, |
||||
'NUMBER': 2, |
||||
'DIFFICULTY': 2, |
||||
'GASLIMIT': 2, |
||||
'POP': 2, |
||||
'MLOAD': 3, |
||||
'MSTORE': 3, |
||||
'MSTORE8': 3, |
||||
'SLOAD': 50, |
||||
'SSTORE': 0, |
||||
'JUMP': 8, |
||||
'JUMPI': 10, |
||||
'PC': 2, |
||||
'MSIZE': 2, |
||||
'GAS': 2, |
||||
'JUMPDEST': 1, |
||||
'LOG0': 375, |
||||
'LOG1': 750, |
||||
'LOG2': 1125, |
||||
'LOG3': 1500, |
||||
'LOG4': 1875, |
||||
'CREATE': 32000, |
||||
'CALL': 40, |
||||
'CALLCODE': 40, |
||||
'RETURN': 0, |
||||
'DELEGATECALL': 40, |
||||
'CALLBLACKBOX': 40, |
||||
'STATICCALL': 40, |
||||
'REVERT': 0, |
||||
'SUICIDE': 5000, |
||||
} |
@ -0,0 +1,122 @@ |
||||
import re |
||||
from z3 import * |
||||
import logging |
||||
|
||||
import sha3 as _sha3 |
||||
import struct |
||||
|
||||
TT256 = 2 ** 256 |
||||
TT256M1 = 2 ** 256 - 1 |
||||
TT255 = 2 ** 255 |
||||
|
||||
|
||||
ALL_BYTES = tuple( |
||||
struct.pack('B', i) |
||||
for i in range(256) |
||||
) |
||||
|
||||
|
||||
|
||||
def zpad(x, l): |
||||
""" Left zero pad value `x` at least to length `l`. |
||||
>>> zpad('\xca\xfe', 4) |
||||
'\x00\x00\xca\xfe' |
||||
""" |
||||
return b'\x00' * max(0, l - len(x)) + x |
||||
|
||||
|
||||
def sha3(seed): |
||||
return _sha3.keccak_256(bytes(seed)).digest() |
||||
|
||||
|
||||
def safe_decode(hex_encoded_string): |
||||
|
||||
if (hex_encoded_string.startswith("0x")): |
||||
return bytes.fromhex(hex_encoded_string[2:]) |
||||
else: |
||||
return bytes.fromhex(hex_encoded_string) |
||||
|
||||
|
||||
def to_signed(i): |
||||
return i if i < TT255 else i - TT256 |
||||
|
||||
|
||||
def get_instruction_index(instruction_list, address): |
||||
|
||||
index = 0 |
||||
|
||||
for instr in instruction_list: |
||||
if instr['address'] == address: |
||||
return index |
||||
|
||||
index += 1 |
||||
|
||||
return None |
||||
|
||||
|
||||
def get_trace_line(instr, state): |
||||
|
||||
stack = str(state.stack[::-1]) |
||||
|
||||
# stack = re.sub("(\d+)", lambda m: hex(int(m.group(1))), stack) |
||||
stack = re.sub("\n", "", stack) |
||||
|
||||
return str(instr['address']) + " " + instr['opcode'] + "\tSTACK: " + stack |
||||
|
||||
|
||||
def pop_bitvec(state): |
||||
# pop one element from stack, converting boolean expressions and |
||||
# concrete Python variables to BitVecVal |
||||
|
||||
item = state.stack.pop() |
||||
|
||||
if type(item) == BoolRef: |
||||
return If(item, BitVecVal(1, 256), BitVecVal(0, 256)) |
||||
elif type(item) == bool: |
||||
if item: |
||||
return BitVecVal(1, 256) |
||||
else: |
||||
return BitVecVal(0, 256) |
||||
elif type(item) == int: |
||||
return BitVecVal(item, 256) |
||||
else: |
||||
return simplify(item) |
||||
|
||||
|
||||
def get_concrete_int(item): |
||||
|
||||
if (type(item) == int): |
||||
return item |
||||
|
||||
if (type(item) == BitVecNumRef): |
||||
return item.as_long() |
||||
|
||||
return simplify(item).as_long() |
||||
|
||||
|
||||
def concrete_int_from_bytes(_bytes, start_index): |
||||
|
||||
# logging.debug("-- concrete_int_from_bytes: " + str(_bytes[start_index:start_index+32])) |
||||
b = _bytes[start_index:start_index+32] |
||||
|
||||
val = int.from_bytes(b, byteorder='big') |
||||
|
||||
return val |
||||
|
||||
|
||||
def concrete_int_to_bytes(val): |
||||
|
||||
# logging.debug("concrete_int_to_bytes " + str(val)) |
||||
|
||||
if (type(val) == int): |
||||
return val.to_bytes(32, byteorder='big') |
||||
|
||||
return (simplify(val).as_long()).to_bytes(32, byteorder='big') |
||||
|
||||
|
||||
def bytearray_to_int(arr): |
||||
o = 0 |
||||
for a in arr: |
||||
o = (o << 8) + a |
||||
return o |
||||
|
@ -0,0 +1,88 @@ |
||||
# -*- coding: utf8 -*- |
||||
|
||||
import copy |
||||
import hashlib |
||||
|
||||
import coincurve |
||||
|
||||
from py_ecc.secp256k1 import N as secp256k1n |
||||
from mythril.laser.ethereum.helper import ALL_BYTES, bytearray_to_int, concrete_int_to_bytes, sha3, zpad |
||||
|
||||
|
||||
def int_to_32bytes(i): #used because int can't fit as bytes function's input |
||||
o = [0] * 32 |
||||
for x in range(32): |
||||
o[31 - x] = i & 0xff |
||||
i >>= 8 |
||||
return bytes(o) |
||||
|
||||
|
||||
def ecrecover_to_pub(rawhash, v, r, s): |
||||
try: |
||||
pk = coincurve.PublicKey.from_signature_and_message( |
||||
zpad(concrete_int_to_bytes(r), 32) + zpad(concrete_int_to_bytes(s), 32) + |
||||
ALL_BYTES[v - 27], |
||||
rawhash, |
||||
hasher=None, |
||||
) |
||||
pub = pk.format(compressed=False)[1:] |
||||
except BaseException: |
||||
pub = b"\x00" * 64 |
||||
|
||||
return pub |
||||
|
||||
|
||||
def extract32(data, i): |
||||
if i >= len(data): |
||||
return 0 |
||||
o = data[i: min(i + 32, len(data))] |
||||
o.extend(bytearray(32 - len(o))) |
||||
return bytearray_to_int(o) |
||||
|
||||
|
||||
def ecrecover(data): |
||||
try: |
||||
data = bytearray(data) |
||||
except TypeError: |
||||
return "ecrecover_"+str(data) |
||||
message = b''.join(map(lambda x: ALL_BYTES[x], data[0:32])) |
||||
v = extract32(data, 32) |
||||
r = extract32(data, 64) |
||||
s = extract32(data, 96) |
||||
if r >= secp256k1n or s >= secp256k1n or v < 27 or v > 28: |
||||
return [] |
||||
try: |
||||
pub = ecrecover_to_pub(message, v, r, s) |
||||
except Exception as e: |
||||
return [] |
||||
o = [0] * 12 + [x for x in sha3(pub)[-20:]] |
||||
return o |
||||
|
||||
|
||||
def sha256(data): |
||||
try: |
||||
data = bytes(data) |
||||
except TypeError: |
||||
return "sha256_"+str(data) |
||||
return hashlib.sha256(data).digest() |
||||
|
||||
|
||||
def ripemd160(data): |
||||
try: |
||||
data = bytes(data) |
||||
except TypeError: |
||||
return "ripemd160_"+str(data) |
||||
return 12*[0]+[i for i in hashlib.new('ripemd160', data).digest()] |
||||
|
||||
|
||||
def identity(data): |
||||
return copy.copy(data) |
||||
|
||||
|
||||
def native_contracts(address, data): |
||||
''' |
||||
takes integer address 1, 2, 3, 4 |
||||
''' |
||||
|
||||
functions = (ecrecover, sha256, ripemd160, identity) |
||||
return functions[address-1](data) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,309 @@ |
||||
import logging, copy |
||||
import mythril.laser.ethereum.helper as helper |
||||
|
||||
|
||||
class TaintRecord: |
||||
""" |
||||
TaintRecord contains tainting information for a specific (state, node) |
||||
the information specifies the taint status before executing the operation belonging to the state |
||||
""" |
||||
|
||||
def __init__(self): |
||||
""" Builds a taint record """ |
||||
self.stack = [] |
||||
self.memory = {} |
||||
self.storage = {} |
||||
self.states = [] |
||||
|
||||
def stack_tainted(self, index): |
||||
""" Returns taint value of stack element at index""" |
||||
if index < len(self.stack): |
||||
return self.stack[index] |
||||
return None |
||||
|
||||
def memory_tainted(self, index): |
||||
""" Returns taint value of memory element at index""" |
||||
if index in self.memory.keys(): |
||||
return self.memory[index] |
||||
return False |
||||
|
||||
def storage_tainted(self, index): |
||||
""" Returns taint value of storage element at index""" |
||||
if index in self.storage.keys(): |
||||
return self.storage[index] |
||||
return False |
||||
|
||||
def add_state(self, state): |
||||
""" Adds state with this taint record """ |
||||
self.states.append(state) |
||||
|
||||
def clone(self): |
||||
""" Clones this record""" |
||||
clone = TaintRecord() |
||||
clone.stack = copy.deepcopy(self.stack) |
||||
clone.memory = copy.deepcopy(self.memory) |
||||
clone.storage = copy.deepcopy(self.storage) |
||||
return clone |
||||
|
||||
|
||||
class TaintResult: |
||||
""" Taint analysis result obtained after having ran the taint runner""" |
||||
|
||||
def __init__(self): |
||||
self.records = [] |
||||
|
||||
def check(self, state, stack_index): |
||||
""" |
||||
Checks if stack variable is tainted, before executing the instruction |
||||
:param state: state to check variable in |
||||
:param stack_index: index of stack variable |
||||
:return: tainted |
||||
""" |
||||
record = self._try_get_record(state) |
||||
if record is None: |
||||
return None |
||||
return record.stack_tainted(stack_index) |
||||
|
||||
def add_records(self, records): |
||||
""" Adds records to this taint result """ |
||||
self.records += records |
||||
|
||||
def _try_get_record(self, state): |
||||
""" Finds record belonging to the state """ |
||||
for record in self.records: |
||||
if state in record.states: |
||||
return record |
||||
return None |
||||
|
||||
|
||||
class TaintRunner: |
||||
""" |
||||
Taint runner, is able to run taint analysis on symbolic execution result |
||||
""" |
||||
|
||||
@staticmethod |
||||
def execute(statespace, node, state, initial_stack=[]): |
||||
""" |
||||
Runs taint analysis on the statespace |
||||
:param statespace: symbolic statespace to run taint analysis on |
||||
:param node: taint introduction node |
||||
:param state: taint introduction state |
||||
:param stack_indexes: stack indexes to introduce taint |
||||
:return: TaintResult object containing analysis results |
||||
""" |
||||
result = TaintResult() |
||||
|
||||
# Build initial current_node |
||||
init_record = TaintRecord() |
||||
init_record.stack = initial_stack |
||||
|
||||
state_index = node.states.index(state) |
||||
|
||||
# List of (Node, TaintRecord, index) |
||||
current_nodes = [(node, init_record, state_index)] |
||||
|
||||
for node, record, index in current_nodes: |
||||
records = TaintRunner.execute_node(node, record, index) |
||||
result.add_records(records) |
||||
|
||||
children = [statespace.nodes[edge.node_to] for edge in statespace.edges if edge.node_from == node.uid] |
||||
for child in children: |
||||
current_nodes.append((child, records[-1], 0)) |
||||
return result |
||||
|
||||
@staticmethod |
||||
def execute_node(node, last_record, state_index=0): |
||||
""" |
||||
Runs taint analysis on a given node |
||||
:param node: node to analyse |
||||
:param last_record: last taint record to work from |
||||
:param state_index: state index to start from |
||||
:return: List of taint records linked to the states in this node |
||||
""" |
||||
records = [last_record] |
||||
for index in range(state_index, len(node.states)): |
||||
current_state = node.states[index] |
||||
records.append(TaintRunner.execute_state(records[-1], current_state)) |
||||
return records[1:] |
||||
|
||||
@staticmethod |
||||
def execute_state(record, state): |
||||
assert len(state.mstate.stack) == len(record.stack) |
||||
""" Runs taint analysis on a state """ |
||||
record.add_state(state) |
||||
new_record = record.clone() |
||||
|
||||
# Apply Change |
||||
op = state.get_current_instruction()['opcode'] |
||||
if op in TaintRunner.stack_taint_table.keys(): |
||||
mutator = TaintRunner.stack_taint_table[op] |
||||
TaintRunner.mutate_stack(new_record, mutator) |
||||
elif op.startswith("PUSH"): |
||||
TaintRunner.mutate_push(op, new_record) |
||||
elif op.startswith("DUP"): |
||||
TaintRunner.mutate_dup(op, new_record) |
||||
elif op.startswith("SWAP"): |
||||
TaintRunner.mutate_swap(op, new_record) |
||||
elif op is "MLOAD": |
||||
TaintRunner.mutate_mload(new_record, state.mstate.stack[-1]) |
||||
elif op.startswith("MSTORE"): |
||||
TaintRunner.mutate_mstore(new_record, state.mstate.stack[-1]) |
||||
elif op is "SLOAD": |
||||
TaintRunner.mutate_sload(new_record, state.mstate.stack[-1]) |
||||
elif op is "SSTORE": |
||||
TaintRunner.mutate_sstore(new_record, state.mstate.stack[-1]) |
||||
elif op.startswith("LOG"): |
||||
TaintRunner.mutate_log(new_record, op) |
||||
elif op in ('CALL', 'CALLCODE', 'DELEGATECALL', 'STATICCALL'): |
||||
TaintRunner.mutate_call(new_record, op) |
||||
else: |
||||
logging.debug("Unknown operation encountered: {}".format(op)) |
||||
|
||||
return new_record |
||||
|
||||
@staticmethod |
||||
def mutate_stack(record, mutator): |
||||
pop, push = mutator |
||||
|
||||
values = [] |
||||
for i in range(pop): |
||||
values.append(record.stack.pop()) |
||||
|
||||
taint = any(values) |
||||
|
||||
for i in range(push): |
||||
record.stack.append(taint) |
||||
|
||||
@staticmethod |
||||
def mutate_push(op, record): |
||||
TaintRunner.mutate_stack(record, (0, 1)) |
||||
|
||||
@staticmethod |
||||
def mutate_dup(op, record): |
||||
depth = int(op[3:]) |
||||
index = len(record.stack) - depth |
||||
record.stack.append(record.stack[index]) |
||||
|
||||
@staticmethod |
||||
def mutate_swap(op, record): |
||||
depth = int(op[4:]) |
||||
l = len(record.stack) - 1 |
||||
i = l - depth |
||||
record.stack[l], record.stack[i] = record.stack[i], record.stack[l] |
||||
|
||||
@staticmethod |
||||
def mutate_mload(record, op0): |
||||
_ = record.stack.pop() |
||||
try: |
||||
index = helper.get_concrete_int(op0) |
||||
except AttributeError: |
||||
logging.debug("Can't MLOAD taint track symbolically") |
||||
record.stack.append(False) |
||||
return |
||||
|
||||
record.stack.append(record.memory_tainted(index)) |
||||
|
||||
@staticmethod |
||||
def mutate_mstore(record, op0): |
||||
_, value_taint = record.stack.pop(), record.stack.pop() |
||||
try: |
||||
index = helper.get_concrete_int(op0) |
||||
except AttributeError: |
||||
logging.debug("Can't mstore taint track symbolically") |
||||
return |
||||
|
||||
record.memory[index] = value_taint |
||||
|
||||
@staticmethod |
||||
def mutate_sload(record, op0): |
||||
_ = record.stack.pop() |
||||
try: |
||||
index = helper.get_concrete_int(op0) |
||||
except AttributeError: |
||||
logging.debug("Can't MLOAD taint track symbolically") |
||||
record.stack.append(False) |
||||
return |
||||
|
||||
record.stack.append(record.storage_tainted(index)) |
||||
|
||||
@staticmethod |
||||
def mutate_sstore(record, op0): |
||||
_, value_taint = record.stack.pop(), record.stack.pop() |
||||
try: |
||||
index = helper.get_concrete_int(op0) |
||||
except AttributeError: |
||||
logging.debug("Can't mstore taint track symbolically") |
||||
return |
||||
|
||||
record.storage[index] = value_taint |
||||
|
||||
@staticmethod |
||||
def mutate_log(record, op): |
||||
depth = int(op[3:]) |
||||
for _ in range(depth + 2): |
||||
record.stack.pop() |
||||
|
||||
@staticmethod |
||||
def mutate_call(record, op): |
||||
pops = 6 |
||||
if op in ('CALL', 'CALLCODE'): |
||||
pops += 1 |
||||
for _ in range(pops): |
||||
record.stack.pop() |
||||
|
||||
record.stack.append(False) |
||||
|
||||
stack_taint_table = { |
||||
# instruction: (taint source, taint target) |
||||
'POP': (1, 0), |
||||
'ADD': (2, 1), |
||||
'MUL': (2, 1), |
||||
'SUB': (2, 1), |
||||
'AND': (2, 1), |
||||
'OR': (2, 1), |
||||
'XOR': (2, 1), |
||||
'NOT': (1, 1), |
||||
'BYTE': (2, 1), |
||||
'DIV': (2, 1), |
||||
'MOD': (2, 1), |
||||
'SDIV': (2, 1), |
||||
'SMOD': (2, 1), |
||||
'ADDMOD': (3, 1), |
||||
'MULMOD': (3, 1), |
||||
'EXP': (2, 1), |
||||
'SIGNEXTEND': (2, 1), |
||||
'LT': (2, 1), |
||||
'GT': (2, 1), |
||||
'SLT': (2, 1), |
||||
'SGT': (2, 1), |
||||
'EQ': (2, 1), |
||||
'ISZERO': (1, 1), |
||||
'CALLVALUE': (0, 1), |
||||
'CALLDATALOAD': (1, 1), |
||||
'CALLDATACOPY': (3, 0), #todo |
||||
'CALLDATASIZE': (0, 1), |
||||
'ADDRESS': (0, 1), |
||||
'BALANCE': (1, 1), |
||||
'ORIGIN': (0, 1), |
||||
'CALLER': (0, 1), |
||||
'CODESIZE': (0, 1), |
||||
'SHA3': (2, 1), |
||||
'GASPRICE': (0, 1), |
||||
'CODECOPY': (3, 0), |
||||
'EXTCODESIZE': (1, 1), |
||||
'EXTCODECOPY': (4, 0), |
||||
'RETURNDATASIZE': (0, 1), |
||||
'BLOCKHASH': (1, 1), |
||||
'COINBASE': (0, 1), |
||||
'TIMESTAMP': (0, 1), |
||||
'NUMBER': (0, 1), |
||||
'DIFFICULTY': (0, 1), |
||||
'GASLIMIT': (0, 1), |
||||
'JUMP': (1, 0), |
||||
'JUMPI': (2, 0), |
||||
'PC': (0, 1), |
||||
'MSIZE': (0, 1), |
||||
'GAS': (0, 1), |
||||
'CREATE': (3, 1), |
||||
'RETURN': (2, 0) |
||||
} |
@ -1,22 +1,23 @@ |
||||
rlp<1.0.0 |
||||
ethereum>=2.3.0 |
||||
ZODB>=5.3.0 |
||||
z3-solver>=4.5 |
||||
laser-ethereum>=0.17.8 |
||||
requests |
||||
BTrees |
||||
plyvel |
||||
py-solc |
||||
pytest |
||||
configparser>=3.5.0 |
||||
coverage |
||||
eth_abi>=1.0.0 |
||||
eth-utils>=1.0.1 |
||||
eth-account>=0.1.0a2 |
||||
ethereum>=2.3.0 |
||||
eth-hash>=0.1.0 |
||||
eth-keyfile>=0.5.1 |
||||
eth-keys>=0.2.0b3 |
||||
eth-rlp>=0.1.0 |
||||
eth-tester>=0.1.0b21 |
||||
coverage |
||||
jinja2 |
||||
attrs |
||||
pytest |
||||
eth-utils>=1.0.1 |
||||
jinja2>=2.9 |
||||
mock |
||||
persistent>=4.2.0 |
||||
plyvel |
||||
py-flags |
||||
py-solc |
||||
pytest>=3.6.0 |
||||
pytest-cov |
||||
pytest_mock |
||||
requests |
||||
rlp<1.0.0 |
||||
z3-solver>=4.5 |
||||
|
@ -0,0 +1,249 @@ |
||||
from mythril.analysis.modules.delegatecall import execute, _concrete_call, _symbolic_call |
||||
from mythril.analysis.ops import Call, Variable, VarType |
||||
from mythril.analysis.symbolic import SymExecWrapper |
||||
from mythril.laser.ethereum.svm import GlobalState, Node, Environment, Account |
||||
import pytest |
||||
from unittest.mock import MagicMock, patch |
||||
import pytest_mock |
||||
|
||||
|
||||
def test_concrete_call(): |
||||
# arrange |
||||
address = "0x10" |
||||
|
||||
state = GlobalState(None, None) |
||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
||||
|
||||
node = Node("example") |
||||
node.contract_name = "the contract name" |
||||
node.function_name = "the function name" |
||||
|
||||
to = Variable(1, VarType.CONCRETE) |
||||
meminstart = Variable(1, VarType.CONCRETE) |
||||
call = Call(node, state, None, None, to, None) |
||||
|
||||
# act |
||||
issues = _concrete_call(call, state, address, meminstart) |
||||
|
||||
# assert |
||||
issue = issues[0] |
||||
assert issue.address == address |
||||
assert issue.contract == node.contract_name |
||||
assert issue.function == node.function_name |
||||
assert issue.title == "Call data forwarded with delegatecall()" |
||||
assert issue.type == 'Informational' |
||||
assert issue.description == "This contract forwards its call data via DELEGATECALL in its fallback function." \ |
||||
" This means that any function in the called contract can be executed." \ |
||||
" Note that the callee contract will have access to the storage of the " \ |
||||
"calling contract.\n DELEGATECALL target: 0x1" |
||||
|
||||
|
||||
def test_concrete_call_symbolic_to(): |
||||
# arrange |
||||
address = "0x10" |
||||
|
||||
state = GlobalState(None, None) |
||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
||||
|
||||
node = Node("example") |
||||
node.contract_name = "the contract name" |
||||
node.function_name = "the function name" |
||||
|
||||
to = Variable("calldata_3", VarType.SYMBOLIC) |
||||
meminstart = Variable(1, VarType.CONCRETE) |
||||
call = Call(node, state, None, None, to, None) |
||||
|
||||
# act |
||||
issues = _concrete_call(call, state, address, meminstart) |
||||
|
||||
# assert |
||||
issue = issues[0] |
||||
assert issue.address == address |
||||
assert issue.contract == node.contract_name |
||||
assert issue.function == node.function_name |
||||
assert issue.title == "Call data forwarded with delegatecall()" |
||||
assert issue.type == 'Informational' |
||||
assert issue.description == "This contract forwards its call data via DELEGATECALL in its fallback function." \ |
||||
" This means that any function in the called contract can be executed." \ |
||||
" Note that the callee contract will have access to the storage of the " \ |
||||
"calling contract.\n DELEGATECALL target: calldata_3" |
||||
|
||||
|
||||
def test_concrete_call_not_calldata(): |
||||
# arrange |
||||
state = GlobalState(None, None) |
||||
state.mstate.memory = ["placeholder", "not_calldata"] |
||||
meminstart = Variable(1, VarType.CONCRETE) |
||||
|
||||
# act |
||||
issues = _concrete_call(None, state, None, meminstart) |
||||
|
||||
# assert |
||||
assert issues == [] |
||||
|
||||
|
||||
def test_symbolic_call_storage_to(mocker): |
||||
# arrange |
||||
address = "0x10" |
||||
|
||||
active_account = Account(address) |
||||
environment = Environment(active_account, None, None, None, None, None) |
||||
state = GlobalState(None, environment) |
||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
||||
|
||||
|
||||
node = Node("example") |
||||
node.contract_name = "the contract name" |
||||
node.function_name = "the function name" |
||||
|
||||
to = Variable("storage_1", VarType.SYMBOLIC) |
||||
call = Call(node, state, None, "Type: ", to, None) |
||||
|
||||
|
||||
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None) |
||||
statespace = SymExecWrapper(1) |
||||
|
||||
mocker.patch.object(statespace, 'find_storage_write') |
||||
statespace.find_storage_write.return_value = "Function name" |
||||
|
||||
|
||||
# act |
||||
issues = _symbolic_call(call, state, address, statespace) |
||||
|
||||
# assert |
||||
issue = issues[0] |
||||
assert issue.address == address |
||||
assert issue.contract == node.contract_name |
||||
assert issue.function == node.function_name |
||||
assert issue.title == 'Type: to a user-supplied address' |
||||
assert issue.type == 'Informational' |
||||
assert issue.description == 'This contract delegates execution to a contract address in storage slot 1.' \ |
||||
' This storage slot can be written to by calling the function `Function name`. ' \ |
||||
'Be aware that the called contract gets unrestricted access to this contract\'s state.' |
||||
|
||||
|
||||
def test_symbolic_call_calldata_to(mocker): |
||||
# arrange |
||||
address = "0x10" |
||||
|
||||
state = GlobalState(None, None) |
||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
||||
|
||||
|
||||
node = Node("example") |
||||
node.contract_name = "the contract name" |
||||
node.function_name = "the function name" |
||||
|
||||
to = Variable("calldata", VarType.SYMBOLIC) |
||||
call = Call(node, state, None, "Type: ", to, None) |
||||
|
||||
|
||||
mocker.patch.object(SymExecWrapper, "__init__", lambda x, y: None) |
||||
statespace = SymExecWrapper(1) |
||||
|
||||
mocker.patch.object(statespace, 'find_storage_write') |
||||
statespace.find_storage_write.return_value = "Function name" |
||||
|
||||
|
||||
# act |
||||
issues = _symbolic_call(call, state, address, statespace) |
||||
|
||||
# assert |
||||
issue = issues[0] |
||||
assert issue.address == address |
||||
assert issue.contract == node.contract_name |
||||
assert issue.function == node.function_name |
||||
assert issue.title == 'Type: to a user-supplied address' |
||||
assert issue.type == 'Informational' |
||||
assert issue.description == 'This contract delegates execution to a contract address obtained from calldata. ' \ |
||||
'Be aware that the called contract gets unrestricted access to this contract\'s state.' |
||||
|
||||
|
||||
@patch('mythril.laser.ethereum.svm.GlobalState.get_current_instruction') |
||||
@patch('mythril.analysis.modules.delegatecall._concrete_call') |
||||
@patch('mythril.analysis.modules.delegatecall._symbolic_call') |
||||
def test_delegate_call(sym_mock, concrete_mock, curr_instruction): |
||||
# arrange |
||||
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call") |
||||
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call") |
||||
sym_mock.return_value = [] |
||||
concrete_mock.return_value = [] |
||||
curr_instruction.return_value = {'address': '0x10'} |
||||
|
||||
active_account = Account('0x10') |
||||
environment = Environment(active_account, None, None, None, None, None) |
||||
state = GlobalState(None, environment) |
||||
state.mstate.memory = ["placeholder", "calldata_bling_0"] |
||||
state.mstate.stack = [1, 2, 3] |
||||
assert state.get_current_instruction() == {'address': '0x10'} |
||||
|
||||
node = Node("example") |
||||
node.contract_name = "the contract name" |
||||
node.function_name = "fallback" |
||||
|
||||
to = Variable("storage_1", VarType.SYMBOLIC) |
||||
call = Call(node, state, None, "DELEGATECALL", to, None) |
||||
|
||||
statespace = MagicMock() |
||||
statespace.calls = [call] |
||||
|
||||
# act |
||||
issues = execute(statespace) |
||||
|
||||
# assert |
||||
assert concrete_mock.call_count == 1 |
||||
assert sym_mock.call_count == 1 |
||||
|
||||
|
||||
@patch('mythril.analysis.modules.delegatecall._concrete_call') |
||||
@patch('mythril.analysis.modules.delegatecall._symbolic_call') |
||||
def test_delegate_call_not_delegate(sym_mock, concrete_mock): |
||||
# arrange |
||||
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call") |
||||
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call") |
||||
sym_mock.return_value = [] |
||||
concrete_mock.return_value = [] |
||||
|
||||
node = Node("example") |
||||
node.function_name = "fallback" |
||||
|
||||
to = Variable("storage_1", VarType.SYMBOLIC) |
||||
call = Call(node, None, None, "NOT_DELEGATECALL", to, None) |
||||
|
||||
statespace = MagicMock() |
||||
statespace.calls = [call] |
||||
|
||||
# act |
||||
issues = execute(statespace) |
||||
|
||||
# assert |
||||
assert issues == [] |
||||
assert concrete_mock.call_count == 0 |
||||
assert sym_mock.call_count == 0 |
||||
|
||||
|
||||
@patch('mythril.analysis.modules.delegatecall._concrete_call') |
||||
@patch('mythril.analysis.modules.delegatecall._symbolic_call') |
||||
def test_delegate_call_not_fallback(sym_mock, concrete_mock): |
||||
# arrange |
||||
# sym_mock = mocker.patch.object(delegatecall, "_symbolic_call") |
||||
# concrete_mock = mocker.patch.object(delegatecall, "_concrete_call") |
||||
sym_mock.return_value = [] |
||||
concrete_mock.return_value = [] |
||||
|
||||
node = Node("example") |
||||
node.function_name = "not_fallback" |
||||
|
||||
to = Variable("storage_1", VarType.SYMBOLIC) |
||||
call = Call(node, None, None, "DELEGATECALL", to, None) |
||||
|
||||
statespace = MagicMock() |
||||
statespace.calls = [call] |
||||
|
||||
# act |
||||
issues = execute(statespace) |
||||
|
||||
# assert |
||||
assert issues == [] |
||||
assert concrete_mock.call_count == 0 |
||||
assert sym_mock.call_count == 0 |
@ -1,32 +0,0 @@ |
||||
from mythril.ether.contractstorage import get_persistent_storage |
||||
import os |
||||
from tests import BaseTestCase |
||||
|
||||
class GetAndSearchContractTestCase(BaseTestCase): |
||||
|
||||
def setUp(self): |
||||
super(GetAndSearchContractTestCase, self).setUp() |
||||
script_path = os.path.dirname(os.path.realpath(__file__)) |
||||
storage_dir = os.path.join(script_path, 'teststorage') |
||||
self.storage, self.db = get_persistent_storage(storage_dir) |
||||
|
||||
def tearDown(self): |
||||
self.db.close() |
||||
super(GetAndSearchContractTestCase, self).tearDown() |
||||
|
||||
def mockCallback(self, code_hash, code, addresses, balances): |
||||
self.code_hash = code_hash |
||||
self.isFound = True |
||||
pass |
||||
|
||||
def runTest(self): |
||||
contract = self.storage.get_contract_by_hash(bytes.fromhex("ea061445eacbe86b7ffed2bb9e52075e")) |
||||
|
||||
self.assertTrue("0x60606040" in contract.code, 'error reading contract code from database') |
||||
|
||||
self.isFound = False |
||||
|
||||
self.storage.search("code#PUSH1#", self.mockCallback) |
||||
|
||||
self.assertTrue(self.isFound, 'storage search error') |
||||
self.assertEqual(self.code_hash, 'ea061445eacbe86b7ffed2bb9e52075e', 'storage search error') |
@ -0,0 +1,117 @@ |
||||
import json |
||||
from mythril.ether.soliditycontract import SolidityContract |
||||
|
||||
from mythril.laser.ethereum.svm import GlobalState, MachineState |
||||
from mythril.laser.ethereum import svm |
||||
from tests import * |
||||
|
||||
|
||||
SHA256_TEST = [ (0,False) for i in range(6)] |
||||
|
||||
RIPEMD160_TEST = [ (0,False) for i in range(6)] |
||||
|
||||
ECRECOVER_TEST = [ (0,False) for i in range(9)] |
||||
|
||||
IDENTITY_TEST = [ (0, False) for i in range(4)] |
||||
|
||||
SHA256_TEST[0] = (5555555555555555, True) #These are Random numbers to check whether the 'if condition' is entered or not(True means entered) |
||||
SHA256_TEST[1] = (323232325445454546, True) |
||||
SHA256_TEST[2] = (34756834765834658, False) |
||||
SHA256_TEST[3] = (8756476956956795876987, True) |
||||
SHA256_TEST[4] = (5763467587689578369, True) |
||||
SHA256_TEST[5] = (948365957658767467857, False) |
||||
|
||||
RIPEMD160_TEST[0] = (1242435356364, True) |
||||
RIPEMD160_TEST[1] = (6732648654386435, True) |
||||
RIPEMD160_TEST[2] = (97457657536546465, False) |
||||
RIPEMD160_TEST[3] = (56436346436456546, True) |
||||
RIPEMD160_TEST[4] = (999999999999999999993, True) |
||||
RIPEMD160_TEST[5] = (1111111111112, False) |
||||
|
||||
|
||||
ECRECOVER_TEST[0] = (786428768768632537676, True) |
||||
ECRECOVER_TEST[1] = (4897983476979346779638, False) |
||||
ECRECOVER_TEST[2] = (674837568743979857398564869, True) |
||||
ECRECOVER_TEST[3] = (3487683476979311, False) |
||||
ECRECOVER_TEST[4] = (853729594875984769847369, True) |
||||
ECRECOVER_TEST[5] = (83579382475972439587, False) |
||||
ECRECOVER_TEST[6] = (8437589437695876985769, True) |
||||
ECRECOVER_TEST[7] = (9486794873598347697596, False) |
||||
ECRECOVER_TEST[8] = (346934876983476, True) |
||||
|
||||
IDENTITY_TEST[0] = (87426857369875698, True) |
||||
IDENTITY_TEST[1] = (476934798798347, False) |
||||
|
||||
IDENTITY_TEST[2] = (7346948379483769, True) |
||||
IDENTITY_TEST[3] = (83269476937987, False) |
||||
|
||||
def _all_info(laser): |
||||
accounts = {} |
||||
for address, _account in laser.accounts.items(): |
||||
account = _account.as_dict() |
||||
account["code"] = account["code"].instruction_list |
||||
account['balance'] = str(account['balance']) |
||||
accounts[address] = account |
||||
|
||||
nodes = {} |
||||
for uid, node in laser.nodes.items(): |
||||
states = [] |
||||
for state in node.states: |
||||
if isinstance(state, MachineState): |
||||
states.append(state.as_dict()) |
||||
elif isinstance(state, GlobalState): |
||||
environment = state.environment.as_dict() |
||||
environment["active_account"] = environment["active_account"].address |
||||
states.append({ |
||||
'accounts': state.accounts.keys(), |
||||
'environment': environment, |
||||
'mstate': state.mstate.as_dict() |
||||
}) |
||||
|
||||
nodes[uid] = { |
||||
'uid': node.uid, |
||||
'contract_name': node.contract_name, |
||||
'start_addr': node.start_addr, |
||||
'states': states, |
||||
'constraints': node.constraints, |
||||
'function_name': node.function_name, |
||||
'flags': str(node.flags) |
||||
} |
||||
|
||||
edges = [edge.as_dict() for edge in laser.edges] |
||||
|
||||
return { |
||||
'accounts': accounts, |
||||
'nodes': nodes, |
||||
'edges': edges, |
||||
'total_states': laser.total_states, |
||||
'max_depth': laser.max_depth |
||||
} |
||||
|
||||
def _test_natives(laser_info, test_list, test_name): |
||||
success = 0 |
||||
for i,j in test_list: |
||||
if (str(i) in laser_info) == j: |
||||
success+=1 |
||||
else: |
||||
print ("Failed: "+str(i)+" "+str(j)) |
||||
assert(success == len(test_list)) |
||||
|
||||
|
||||
|
||||
class NativeTests(BaseTestCase): |
||||
def runTest(self): |
||||
disassembly = SolidityContract('./tests/native_tests.sol').disassembly |
||||
account = svm.Account("0x0000000000000000000000000000000000000000", disassembly) |
||||
accounts = {account.address: account} |
||||
|
||||
laser = svm.LaserEVM(accounts, max_depth = 100) |
||||
laser.sym_exec(account.address) |
||||
laser_info = str(_all_info(laser)) |
||||
print('\n') |
||||
|
||||
_test_natives(laser_info, SHA256_TEST, 'SHA256') |
||||
_test_natives(laser_info, RIPEMD160_TEST, 'RIPEMD160') |
||||
_test_natives(laser_info, ECRECOVER_TEST, 'ECRECOVER') |
||||
_test_natives(laser_info, IDENTITY_TEST, 'IDENTITY') |
||||
|
@ -0,0 +1,166 @@ |
||||
pragma solidity ^0.4.17; |
||||
|
||||
|
||||
contract Caller { |
||||
|
||||
address public fixed_address; //Just some useless variables |
||||
address public stored_address; |
||||
|
||||
uint256 statevar; //useless( but good for testing as they contribute as decoys) |
||||
bytes32 far; |
||||
|
||||
function Caller(address addr) { |
||||
fixed_address = addr; |
||||
} |
||||
|
||||
function thisisfine() public { //some typical function as a decoy |
||||
fixed_address.call(); |
||||
} |
||||
function sha256_test1() public { |
||||
uint256 i; |
||||
if(sha256('ab','c') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True |
||||
i = 5555555555555555; |
||||
} |
||||
|
||||
if(sha256('abc') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad){ //True |
||||
i = 323232325445454546; |
||||
} |
||||
} |
||||
function sha256_test2() public { |
||||
uint256 i; |
||||
if(sha256('abd') == 0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad) { //False |
||||
i = 34756834765834658; |
||||
} |
||||
if(sha256('ab','d') == 0xa52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9) { //True |
||||
i = 8756476956956795876987; |
||||
} |
||||
} |
||||
function sha256_test3() public { |
||||
uint256 i; |
||||
if(sha256('') == 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855) { //True |
||||
i = 5763467587689578369; |
||||
} |
||||
if(sha256('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhfdhhfdhhhhhh') == 0xe4ebd771f821e3277b77dcc39e94fe7172a5c9c8c12f8885c2d5513385a0a8b8) { //False |
||||
i = 948365957658767467857; |
||||
} |
||||
} |
||||
|
||||
function ripemd_test1() public { |
||||
uint256 i; |
||||
if(ripemd160('ab','c') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True |
||||
i = 1242435356364; |
||||
} |
||||
if(ripemd160('abc') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc){ //True |
||||
i = 6732648654386435; |
||||
} |
||||
} |
||||
function ripemd_test2() public { |
||||
uint256 i; |
||||
if(ripemd160('abd') == 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc) { //False |
||||
i = 97457657536546465; |
||||
} |
||||
if(ripemd160('ab','d') == 0xb0a79cc77e333ea11974e105cd051d33836928b0) { //True |
||||
i = 56436346436456546; |
||||
} |
||||
} |
||||
function ripemd_test3() public { |
||||
uint256 i; |
||||
if(ripemd160('') == 0x9c1185a5c5e9fc54612808977ee8f548b2258d31) { //True |
||||
i = 999999999999999999993; |
||||
} |
||||
if(ripemd160('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh') == 0x2d1b88a5daa5d138eb7bb14ee320010937f0ebe7) { //False |
||||
i = 1111111111112; |
||||
} |
||||
} |
||||
|
||||
function ecrecover_test1() public { |
||||
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; |
||||
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; |
||||
bytes32 prefixedHash = keccak256(prefix, foobar); |
||||
uint8 v = 28; |
||||
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; |
||||
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; |
||||
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8a) { //True |
||||
uint256 bignum = 786428768768632537676; |
||||
} |
||||
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False |
||||
uint256 small = 4897983476979346779638; |
||||
} |
||||
foobar = 0x38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; |
||||
if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //True |
||||
uint256 dk = 674837568743979857398564869; |
||||
} |
||||
foobar = 0x38d18acb67d25c7bb9942764b62f18e17054f66a817bd4295423adf9ed98873e; //not same as above, minor change(7bb instead of 8bb) |
||||
if( ecrecover( keccak256(foobar), v, r, s) == 0x0faf91ea0aaaa5377dfdf188b21409007f0b4019) { //False |
||||
uint256 pk = 3487683476979311; |
||||
} |
||||
|
||||
} |
||||
|
||||
function ecrecover_test2() public { |
||||
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; |
||||
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; |
||||
bytes32 prefixedHash = keccak256(prefix, foobar); |
||||
uint8 v = 26; |
||||
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; |
||||
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; |
||||
if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True |
||||
uint256 bignum = 853729594875984769847369; |
||||
} |
||||
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False |
||||
uint256 small = 83579382475972439587; |
||||
} |
||||
} |
||||
function ecrecover_test3() public { |
||||
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; |
||||
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; |
||||
bytes32 prefixedHash = keccak256(prefix, foobar); |
||||
uint8 v = 29; |
||||
bytes32 r = 0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608; |
||||
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; |
||||
if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True |
||||
uint256 bignum = 8437589437695876985769; |
||||
} |
||||
if( ecrecover(prefixedHash, v, r, s) == 0x7156526fbd7a3c72969b54f64e42c10fbb768c8b) { //False |
||||
uint256 small = 9486794873598347697596; |
||||
} |
||||
} |
||||
function ecrecover_test4() public { |
||||
bytes32 foobar = 0x1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8; |
||||
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; |
||||
bytes32 prefixedHash = keccak256(prefix, foobar); |
||||
uint8 v = 27; |
||||
bytes32 r = 0xfffffffffffffffffffffffffffffffffaaedce6af48a03bbfd25e8cd0364141; //greater than the max limit |
||||
bytes32 s = 0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada; |
||||
|
||||
if( ecrecover(prefixedHash, v, r, s) == 0x0000000000000000000000000000000000000000) { //True |
||||
uint256 bignum = 346934876983476; |
||||
} |
||||
} |
||||
function need_identity_invoke(uint sea) returns (uint) { |
||||
return sea; //identity is invoked here in compiler and not below |
||||
} |
||||
function identity_function(int input) public returns(int out) { |
||||
assembly{ |
||||
let x := mload(0x40) |
||||
mstore(x, input) |
||||
|
||||
let success := call(500000000, 0x4, 100000, x, 0x20, x, 0x20) |
||||
out := mload(x) |
||||
mstore(0x40, x) |
||||
} |
||||
} |
||||
function identity_test1() public{ |
||||
if(identity_function(100)==100) //True |
||||
uint256 smallnum = 87426857369875698; |
||||
if(identity_function(200)==100) //False |
||||
uint256 bignum = 476934798798347; |
||||
} |
||||
function identity_test2() public{ |
||||
if(identity_function(12345678)==12345678) //True |
||||
uint256 smallnum = 7346948379483769; |
||||
if(identity_function(74648796976)==4685987) //False |
||||
uint256 bignum = 83269476937987; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,29 @@ |
||||
from mythril.laser.ethereum.taint_analysis import * |
||||
|
||||
def test_mutate_not_tainted(): |
||||
# Arrange |
||||
record = TaintRecord() |
||||
|
||||
record.stack = [True, False, False] |
||||
# Act |
||||
TaintRunner.mutate_stack(record, (2,1)) |
||||
|
||||
# Assert |
||||
assert record.stack_tainted(0) |
||||
assert record.stack_tainted(1) is False |
||||
assert record.stack == [True, False] |
||||
|
||||
|
||||
def test_mutate_tainted(): |
||||
# Arrange |
||||
record = TaintRecord() |
||||
|
||||
record.stack = [True, False, True] |
||||
|
||||
# Act |
||||
TaintRunner.mutate_stack(record, (2, 1)) |
||||
|
||||
# Assert |
||||
assert record.stack_tainted(0) |
||||
assert record.stack_tainted(1) |
||||
assert record.stack == [True, True] |
@ -0,0 +1,36 @@ |
||||
from mythril.laser.ethereum.taint_analysis import * |
||||
|
||||
|
||||
def test_record_tainted_check(): |
||||
# arrange |
||||
record = TaintRecord() |
||||
record.stack = [True, False, True] |
||||
|
||||
# act |
||||
tainted = record.stack_tainted(2) |
||||
|
||||
# assert |
||||
assert tainted is True |
||||
|
||||
|
||||
def test_record_untainted_check(): |
||||
# arrange |
||||
record = TaintRecord() |
||||
record.stack = [True, False, False] |
||||
|
||||
# act |
||||
tainted = record.stack_tainted(2) |
||||
|
||||
# assert |
||||
assert tainted is False |
||||
|
||||
|
||||
def test_record_untouched_check(): |
||||
# arrange |
||||
record = TaintRecord() |
||||
|
||||
# act |
||||
tainted = record.stack_tainted(3) |
||||
|
||||
# assert |
||||
assert tainted is None |
@ -0,0 +1,36 @@ |
||||
from mythril.laser.ethereum.taint_analysis import * |
||||
from mythril.laser.ethereum.svm import GlobalState |
||||
|
||||
|
||||
def test_result_state(): |
||||
# arrange |
||||
taint_result = TaintResult() |
||||
record = TaintRecord() |
||||
state = GlobalState(2, None) |
||||
state.mstate.stack = [1,2,3] |
||||
record.add_state(state) |
||||
record.stack = [False, False, False] |
||||
# act |
||||
taint_result.add_records([record]) |
||||
tainted = taint_result.check(state, 2) |
||||
|
||||
# assert |
||||
assert tainted is False |
||||
assert record in taint_result.records |
||||
|
||||
|
||||
def test_result_no_state(): |
||||
# arrange |
||||
taint_result = TaintResult() |
||||
record = TaintRecord() |
||||
state = GlobalState(2, None) |
||||
state.mstate.stack = [1,2,3] |
||||
|
||||
|
||||
# act |
||||
taint_result.add_records([record]) |
||||
tainted = taint_result.check(state, 2) |
||||
|
||||
# assert |
||||
assert tainted is None |
||||
assert record in taint_result.records |
@ -0,0 +1,94 @@ |
||||
import mock |
||||
import pytest |
||||
from pytest_mock import mocker |
||||
from mythril.laser.ethereum.taint_analysis import * |
||||
from mythril.laser.ethereum.svm import GlobalState, Node, Edge, LaserEVM, MachineState |
||||
|
||||
|
||||
def test_execute_state(mocker): |
||||
record = TaintRecord() |
||||
record.stack = [True, False, True] |
||||
|
||||
state = GlobalState(None, None) |
||||
state.mstate.stack = [1, 2, 3] |
||||
mocker.patch.object(state, 'get_current_instruction') |
||||
state.get_current_instruction.return_value = {"opcode": "ADD"} |
||||
|
||||
# Act |
||||
new_record = TaintRunner.execute_state(record, state) |
||||
|
||||
# Assert |
||||
assert new_record.stack == [True, True] |
||||
assert record.stack == [True, False, True] |
||||
|
||||
|
||||
def test_execute_node(mocker): |
||||
record = TaintRecord() |
||||
record.stack = [True, True, False, False] |
||||
|
||||
state_1 = GlobalState(None, None) |
||||
state_1.mstate.stack = [1, 2, 3] |
||||
state_1.mstate.pc = 1 |
||||
mocker.patch.object(state_1, 'get_current_instruction') |
||||
state_1.get_current_instruction.return_value = {"opcode": "SWAP1"} |
||||
|
||||
state_2 = GlobalState(None, 1) |
||||
state_2.mstate.stack = [1, 2, 4, 1] |
||||
mocker.patch.object(state_2, 'get_current_instruction') |
||||
state_2.get_current_instruction.return_value = {"opcode": "ADD"} |
||||
|
||||
node = Node("Test contract") |
||||
node.states = [state_1, state_2] |
||||
|
||||
# Act |
||||
records = TaintRunner.execute_node(node, record) |
||||
|
||||
# Assert |
||||
assert len(records) == 2 |
||||
|
||||
assert records[0].stack == [True, True, False, False] |
||||
assert records[1].stack == [True, True, False] |
||||
|
||||
assert state_2 in records[0].states |
||||
assert state_1 in record.states |
||||
|
||||
|
||||
|
||||
|
||||
def test_execute(mocker): |
||||
state_1 = GlobalState(None, None, MachineState(gas=10000000)) |
||||
state_1.mstate.stack = [1, 2] |
||||
mocker.patch.object(state_1, 'get_current_instruction') |
||||
state_1.get_current_instruction.return_value = {"opcode": "PUSH"} |
||||
|
||||
state_2 = GlobalState(None, None, MachineState(gas=10000000)) |
||||
state_2.mstate.stack = [1, 2, 3] |
||||
mocker.patch.object(state_2, 'get_current_instruction') |
||||
state_2.get_current_instruction.return_value = {"opcode": "ADD"} |
||||
|
||||
node_1 = Node("Test contract") |
||||
node_1.states = [state_1, state_2] |
||||
|
||||
state_3 = GlobalState(None, None, MachineState(gas=10000000)) |
||||
state_3.mstate.stack = [1, 2] |
||||
mocker.patch.object(state_3, 'get_current_instruction') |
||||
state_3.get_current_instruction.return_value = {"opcode": "ADD"} |
||||
|
||||
node_2 = Node("Test contract") |
||||
node_2.states = [state_3] |
||||
|
||||
edge = Edge(node_1.uid, node_2.uid) |
||||
|
||||
statespace = LaserEVM(None) |
||||
statespace.edges = [edge] |
||||
statespace.nodes[node_1.uid] = node_1 |
||||
statespace.nodes[node_2.uid] = node_2 |
||||
|
||||
# Act |
||||
result = TaintRunner.execute(statespace, node_1, state_1, [True, True]) |
||||
|
||||
# Assert |
||||
print(result) |
||||
assert len(result.records) == 3 |
||||
assert result.records[2].states == [] |
||||
assert state_3 in result.records[1].states |
@ -0,0 +1,6 @@ |
||||
pragma solidity ^0.4.22; |
||||
contract nonAscii { |
||||
function renderNonAscii () public pure returns (string) { |
||||
return "Хэллоу Ворлд"; |
||||
} |
||||
} |
@ -0,0 +1,152 @@ |
||||
contract Rubixi { |
||||
|
||||
//Declare variables for storage critical to contract |
||||
uint private balance = 0; |
||||
uint private collectedFees = 0; |
||||
uint private feePercent = 10; |
||||
uint private pyramidMultiplier = 300; |
||||
uint private payoutOrder = 0; |
||||
|
||||
address private creator; |
||||
|
||||
//Sets creator |
||||
function DynamicPyramid() { |
||||
creator = msg.sender; |
||||
} |
||||
|
||||
modifier onlyowner { |
||||
if (msg.sender == creator) _; |
||||
} |
||||
|
||||
struct Participant { |
||||
address etherAddress; |
||||
uint payout; |
||||
} |
||||
|
||||
Participant[] private participants; |
||||
|
||||
//Fallback function |
||||
function() { |
||||
init(); |
||||
} |
||||
|
||||
//init function run on fallback |
||||
function init() private { |
||||
//Ensures only tx with value of 1 ether or greater are processed and added to pyramid |
||||
if (msg.value < 1 ether) { |
||||
collectedFees += msg.value; |
||||
return; |
||||
} |
||||
|
||||
uint _fee = feePercent; |
||||
//50% fee rebate on any ether value of 50 or greater |
||||
if (msg.value >= 50 ether) _fee /= 2; |
||||
|
||||
addPayout(_fee); |
||||
} |
||||
|
||||
//Function called for valid tx to the contract |
||||
function addPayout(uint _fee) private { |
||||
//Adds new address to participant array |
||||
participants.push(Participant(msg.sender, (msg.value * pyramidMultiplier) / 100)); |
||||
|
||||
//These statements ensure a quicker payout system to later pyramid entrants, so the pyramid has a longer lifespan |
||||
if (participants.length == 10) pyramidMultiplier = 200; |
||||
else if (participants.length == 25) pyramidMultiplier = 150; |
||||
|
||||
// collect fees and update contract balance |
||||
balance += (msg.value * (100 - _fee)) / 100; |
||||
collectedFees += (msg.value * _fee) / 100; |
||||
|
||||
//Pays earlier participiants if balance sufficient |
||||
while (balance > participants[payoutOrder].payout) { |
||||
uint payoutToSend = participants[payoutOrder].payout; |
||||
participants[payoutOrder].etherAddress.send(payoutToSend); |
||||
|
||||
balance -= participants[payoutOrder].payout; |
||||
payoutOrder += 1; |
||||
} |
||||
} |
||||
|
||||
//Fee functions for creator |
||||
function collectAllFees() onlyowner { |
||||
if (collectedFees == 0) throw; |
||||
|
||||
creator.send(collectedFees); |
||||
collectedFees = 0; |
||||
} |
||||
|
||||
function collectFeesInEther(uint _amt) onlyowner { |
||||
_amt *= 1 ether; |
||||
if (_amt > collectedFees) collectAllFees(); |
||||
|
||||
if (collectedFees == 0) throw; |
||||
|
||||
creator.send(_amt); |
||||
collectedFees -= _amt; |
||||
} |
||||
|
||||
function collectPercentOfFees(uint _pcent) onlyowner { |
||||
if (collectedFees == 0 || _pcent > 100) throw; |
||||
|
||||
uint feesToCollect = collectedFees / 100 * _pcent; |
||||
creator.send(feesToCollect); |
||||
collectedFees -= feesToCollect; |
||||
} |
||||
|
||||
//Functions for changing variables related to the contract |
||||
function changeOwner(address _owner) onlyowner { |
||||
creator = _owner; |
||||
} |
||||
|
||||
function changeMultiplier(uint _mult) onlyowner { |
||||
if (_mult > 300 || _mult < 120) throw; |
||||
|
||||
pyramidMultiplier = _mult; |
||||
} |
||||
|
||||
function changeFeePercentage(uint _fee) onlyowner { |
||||
if (_fee > 10) throw; |
||||
|
||||
feePercent = _fee; |
||||
} |
||||
|
||||
//Functions to provide information to end-user using JSON interface or other interfaces |
||||
function currentMultiplier() constant returns(uint multiplier, string info) { |
||||
multiplier = pyramidMultiplier; |
||||
info = 'This multiplier applies to you as soon as transaction is received, may be lowered to hasten payouts or increased if payouts are fast enough. Due to no float or decimals, multiplier is x100 for a fractional multiplier e.g. 250 is actually a 2.5x multiplier. Capped at 3x max and 1.2x min.'; |
||||
} |
||||
|
||||
function currentFeePercentage() constant returns(uint fee, string info) { |
||||
fee = feePercent; |
||||
info = 'Shown in % form. Fee is halved(50%) for amounts equal or greater than 50 ethers. (Fee may change, but is capped to a maximum of 10%)'; |
||||
} |
||||
|
||||
function currentPyramidBalanceApproximately() constant returns(uint pyramidBalance, string info) { |
||||
pyramidBalance = balance / 1 ether; |
||||
info = 'All balance values are measured in Ethers, note that due to no decimal placing, these values show up as integers only, within the contract itself you will get the exact decimal value you are supposed to'; |
||||
} |
||||
|
||||
function nextPayoutWhenPyramidBalanceTotalsApproximately() constant returns(uint balancePayout) { |
||||
balancePayout = participants[payoutOrder].payout / 1 ether; |
||||
} |
||||
|
||||
function feesSeperateFromBalanceApproximately() constant returns(uint fees) { |
||||
fees = collectedFees / 1 ether; |
||||
} |
||||
|
||||
function totalParticipants() constant returns(uint count) { |
||||
count = participants.length; |
||||
} |
||||
|
||||
function numberOfParticipantsWaitingForPayout() constant returns(uint count) { |
||||
count = participants.length - payoutOrder; |
||||
} |
||||
|
||||
function participantDetails(uint orderInPyramid) constant returns(address Address, uint Payout) { |
||||
if (orderInPyramid <= participants.length) { |
||||
Address = participants[orderInPyramid].etherAddress; |
||||
Payout = participants[orderInPyramid].payout / 1 ether; |
||||
} |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
606060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806312065fe01461008257806327e235e3146100ab57806356885cd8146100f85780636c343ffe1461010d5780638da5cb5b14610122578063e8b5e51f14610177575b610080610181565b005b341561008d57600080fd5b6100956101ec565b6040518082815260200191505060405180910390f35b34156100b657600080fd5b6100e2600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610232565b6040518082815260200191505060405180910390f35b341561010357600080fd5b61010b61024a565b005b341561011857600080fd5b61012061028d565b005b341561012d57600080fd5b610135610342565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61017f610181565b005b60025434118015610193575060035434105b151561019e57600080fd5b346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540192505081905550565b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905090565b60006020528060005260406000206000915090505481565b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102e957600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f19350505050151561034057600080fd5b565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a72305820bbf8d45345e3ef7004b6445155bc5f20c8a6dc61dec2637ed9f5eb80f5b2ab0a0029 |
||||
608060405260043610610078576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806312065fe01461007d57806327e235e3146100a857806356885cd8146100ff5780636c343ffe146101165780638da5cb5b1461012d578063e8b5e51f14610184575b600080fd5b34801561008957600080fd5b5061009261018e565b6040518082815260200191505060405180910390f35b3480156100b457600080fd5b506100e9600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506101d4565b6040518082815260200191505060405180910390f35b34801561010b57600080fd5b506101146101ec565b005b34801561012257600080fd5b5061012b61022f565b005b34801561013957600080fd5b506101426102eb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61018c610311565b005b60008060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905090565b60006020528060005260406000206000915090505481565b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561028b57600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc3073ffffffffffffffffffffffffffffffffffffffff16319081150290604051600060405180830381858888f193505050501580156102e8573d6000803e3d6000fd5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025434118015610323575060035434105b151561032e57600080fd5b346000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505600a165627a7a72305820402df619c16e4325eb7830ed063880a283ac25dff982b6a5be67138df0c209550029 |
@ -0,0 +1 @@ |
||||
608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806324ff38a214610046575b600080fd5b34801561005257600080fd5b5061005b6100d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561009b578082015181840152602081019050610080565b50505050905090810190601f1680156100c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60606040805190810160405280601781526020017fd0a5d18dd0bbd0bbd0bed18320d092d0bed180d0bbd0b40000000000000000008152509050905600a165627a7a72305820a11284868fc6a38ff1d72ce9ec40db9c6c7c49902b5cabec3680e88e5ab92dcb0029 |
File diff suppressed because one or more lines are too long
@ -0,0 +1,167 @@ |
||||
0 PUSH1 0x80 |
||||
2 PUSH1 0x40 |
||||
4 MSTORE |
||||
5 PUSH1 0x04 |
||||
7 CALLDATASIZE |
||||
8 LT |
||||
9 PUSH2 0x0041 |
||||
12 JUMPI |
||||
13 PUSH1 0x00 |
||||
15 CALLDATALOAD |
||||
16 PUSH29 0x0100000000000000000000000000000000000000000000000000000000 |
||||
46 SWAP1 |
||||
47 DIV |
||||
48 PUSH4 0xffffffff |
||||
53 AND |
||||
54 DUP1 |
||||
55 PUSH4 0x24ff38a2 |
||||
60 EQ |
||||
61 PUSH2 0x0046 |
||||
64 JUMPI |
||||
65 JUMPDEST |
||||
66 PUSH1 0x00 |
||||
68 DUP1 |
||||
69 REVERT |
||||
70 JUMPDEST |
||||
71 CALLVALUE |
||||
72 DUP1 |
||||
73 ISZERO |
||||
74 PUSH2 0x0052 |
||||
77 JUMPI |
||||
78 PUSH1 0x00 |
||||
80 DUP1 |
||||
81 REVERT |
||||
82 JUMPDEST |
||||
83 POP |
||||
84 PUSH2 0x005b |
||||
87 PUSH2 0x00d6 |
||||
90 JUMP |
||||
91 JUMPDEST |
||||
92 PUSH1 0x40 |
||||
94 MLOAD |
||||
95 DUP1 |
||||
96 DUP1 |
||||
97 PUSH1 0x20 |
||||
99 ADD |
||||
100 DUP3 |
||||
101 DUP2 |
||||
102 SUB |
||||
103 DUP3 |
||||
104 MSTORE |
||||
105 DUP4 |
||||
106 DUP2 |
||||
107 DUP2 |
||||
108 MLOAD |
||||
109 DUP2 |
||||
110 MSTORE |
||||
111 PUSH1 0x20 |
||||
113 ADD |
||||
114 SWAP2 |
||||
115 POP |
||||
116 DUP1 |
||||
117 MLOAD |
||||
118 SWAP1 |
||||
119 PUSH1 0x20 |
||||
121 ADD |
||||
122 SWAP1 |
||||
123 DUP1 |
||||
124 DUP4 |
||||
125 DUP4 |
||||
126 PUSH1 0x00 |
||||
128 JUMPDEST |
||||
129 DUP4 |
||||
130 DUP2 |
||||
131 LT |
||||
132 ISZERO |
||||
133 PUSH2 0x009b |
||||
136 JUMPI |
||||
137 DUP1 |
||||
138 DUP3 |
||||
139 ADD |
||||
140 MLOAD |
||||
141 DUP2 |
||||
142 DUP5 |
||||
143 ADD |
||||
144 MSTORE |
||||
145 PUSH1 0x20 |
||||
147 DUP2 |
||||
148 ADD |
||||
149 SWAP1 |
||||
150 POP |
||||
151 PUSH2 0x0080 |
||||
154 JUMP |
||||
155 JUMPDEST |
||||
156 POP |
||||
157 POP |
||||
158 POP |
||||
159 POP |
||||
160 SWAP1 |
||||
161 POP |
||||
162 SWAP1 |
||||
163 DUP2 |
||||
164 ADD |
||||
165 SWAP1 |
||||
166 PUSH1 0x1f |
||||
168 AND |
||||
169 DUP1 |
||||
170 ISZERO |
||||
171 PUSH2 0x00c8 |
||||
174 JUMPI |
||||
175 DUP1 |
||||
176 DUP3 |
||||
177 SUB |
||||
178 DUP1 |
||||
179 MLOAD |
||||
180 PUSH1 0x01 |
||||
182 DUP4 |
||||
183 PUSH1 0x20 |
||||
185 SUB |
||||
186 PUSH2 0x0100 |
||||
189 EXP |
||||
190 SUB |
||||
191 NOT |
||||
192 AND |
||||
193 DUP2 |
||||
194 MSTORE |
||||
195 PUSH1 0x20 |
||||
197 ADD |
||||
198 SWAP2 |
||||
199 POP |
||||
200 JUMPDEST |
||||
201 POP |
||||
202 SWAP3 |
||||
203 POP |
||||
204 POP |
||||
205 POP |
||||
206 PUSH1 0x40 |
||||
208 MLOAD |
||||
209 DUP1 |
||||
210 SWAP2 |
||||
211 SUB |
||||
212 SWAP1 |
||||
213 RETURN |
||||
214 JUMPDEST |
||||
215 PUSH1 0x60 |
||||
217 PUSH1 0x40 |
||||
219 DUP1 |
||||
220 MLOAD |
||||
221 SWAP1 |
||||
222 DUP2 |
||||
223 ADD |
||||
224 PUSH1 0x40 |
||||
226 MSTORE |
||||
227 DUP1 |
||||
228 PUSH1 0x17 |
||||
230 DUP2 |
||||
231 MSTORE |
||||
232 PUSH1 0x20 |
||||
234 ADD |
||||
235 PUSH32 0xd0a5d18dd0bbd0bbd0bed18320d092d0bed180d0bbd0b4000000000000000000 |
||||
268 DUP2 |
||||
269 MSTORE |
||||
270 POP |
||||
271 SWAP1 |
||||
272 POP |
||||
273 SWAP1 |
||||
274 JUMP |
||||
275 STOP |
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@ |
||||
{"error": null, "issues": [], "success": true} |
@ -0,0 +1,3 @@ |
||||
# Analysis results for None |
||||
|
||||
The analysis was completed successfully. No issues were detected. |
@ -0,0 +1 @@ |
||||
The analysis was completed successfully. No issues were detected. |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue