├── examples ├── justlen.yaml └── justlen.sol ├── scripts └── pyfile_exists.py ├── echidna_parade ├── config.py ├── __main__.py ├── echidna.py └── campaign.py ├── .github └── workflows │ └── ci.yml ├── setup.py ├── .gitignore ├── README.md └── LICENSE /examples/justlen.yaml: -------------------------------------------------------------------------------- 1 | checkAsserts: true 2 | testMode: assertion 3 | testLimit: 1000000 4 | timeout: 120 5 | -------------------------------------------------------------------------------- /scripts/pyfile_exists.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | 6 | # Checks whether files listed via stdin actually exist 7 | for f in sys.stdin.readlines(): 8 | line = f.strip() 9 | if line.endswith(".py") and os.path.exists(line): 10 | print(line) 11 | -------------------------------------------------------------------------------- /echidna_parade/config.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | from collections import namedtuple 4 | from yaml import safe_load 5 | from os import getpid 6 | 7 | 8 | def create_parade_config(pargs, parser): 9 | """ 10 | Process the raw arguments, returning a namedtuple object holding the 11 | entire configuration, if everything parses correctly. 12 | """ 13 | pdict = pargs.__dict__ 14 | if pargs.name is None: 15 | pargs.name = "parade." + str(getpid()) 16 | 17 | if pargs.files is None: 18 | parser.print_help() 19 | raise ValueError("You must specify some files to test!") 20 | # create a namedtuple object for fast attribute lookup 21 | key_list = list(pdict.keys()) 22 | arg_list = [pdict[k] for k in key_list] 23 | 24 | Config = namedtuple("Config", key_list) 25 | nt_config = Config(*arg_list) 26 | return nt_config 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | lint: 13 | runs-on: ubuntu-18.04 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Set up Python 3.6 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: 3.6 20 | - name: Lint 21 | env: 22 | BASE_SHA: ${{ github.event.pull_request.base.sha }} 23 | run: | 24 | pip install .[lint] 25 | black --version 26 | git fetch --depth=1 origin $BASE_SHA 27 | echo "Files Changed:" 28 | git diff --name-only $BASE_SHA... | tee .diff_names.txt 29 | NAMES=$(cat .diff_names.txt | python scripts/pyfile_exists.py) 30 | if test -z $NAMES 31 | then 32 | black --diff --check . 33 | else 34 | echo $NAMES | xargs black --diff --check 35 | fi 36 | mypy --version 37 | mypy --ignore-missing-imports echidna_parade 38 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from setuptools import setup 4 | 5 | lint_deps = ["black==20.8b1", "mypy==0.790"] 6 | 7 | extra_require = { 8 | "lint": lint_deps, 9 | } 10 | 11 | setup( 12 | name="echidna-parade", 13 | version="0.1", 14 | description="Meta-tool to test a contract with various configs, using Echidna processes", 15 | long_description_content_type="text/markdown", 16 | long_description=open("README.md").read(), 17 | packages=[ 18 | "echidna_parade", 19 | ], 20 | license="AGPL3", 21 | entry_points=""" 22 | [console_scripts] 23 | echidna-parade = echidna_parade.__main__:main 24 | """, 25 | keywords="echidna smart-contracts testing fuzzing swarm test-diversity", 26 | test_suite="nose.collector", 27 | tests_require=["nose"], 28 | classifiers=[ 29 | "Intended Audience :: Developers", 30 | "Development Status :: 4 - Beta", 31 | "Programming Language :: Python :: 3", 32 | ], 33 | install_requires=["pyyaml", "slither-analyzer", "crytic-compile"], 34 | extras_require=extra_require, 35 | url="https://github.com/crytic/echidna-parade", 36 | ) 37 | -------------------------------------------------------------------------------- /examples/justlen.sol: -------------------------------------------------------------------------------- 1 | contract TEST { 2 | 3 | address [] add_array; 4 | 5 | bool lengthChecking = false; 6 | 7 | function push_1(address x) public { 8 | add_array.push(x); 9 | } 10 | 11 | function pop_1() public { 12 | if (add_array.length > 0) { 13 | add_array.pop(); 14 | } 15 | } 16 | 17 | function double(address x) public { 18 | uint alen = add_array.length; 19 | for (uint i = 0; i < alen; i++) { 20 | add_array.push(x); 21 | } 22 | } 23 | 24 | function plus5(address x) public { 25 | uint alen = add_array.length; 26 | for (uint i = 0; i < 5; i++) { 27 | add_array.push(x); 28 | } 29 | } 30 | 31 | function halve() public { 32 | uint alen = add_array.length; 33 | for (uint i = 0; i < (alen/2); i++) { 34 | add_array.pop(); 35 | } 36 | } 37 | 38 | function decimate() public { 39 | uint alen = add_array.length; 40 | for (uint i = 0; i < ((alen*9)/10); i++) { 41 | add_array.pop(); 42 | } 43 | } 44 | 45 | function empty1() public { 46 | delete add_array; 47 | } 48 | 49 | function empty2() public { 50 | delete add_array; 51 | } 52 | 53 | function empty3() public { 54 | delete add_array; 55 | } 56 | 57 | function turn_on_length_checking() public { 58 | lengthChecking = true; 59 | } 60 | 61 | function turn_off_length_checking() public { 62 | lengthChecking = false; 63 | } 64 | 65 | function test_long_8() public view { 66 | if (add_array.length >= 8) { 67 | if (lengthChecking) { 68 | assert(false); 69 | } 70 | } 71 | } 72 | 73 | function test_long_64() public view { 74 | if (add_array.length >= 64) { 75 | if (lengthChecking) { 76 | assert(false); 77 | } 78 | } 79 | } 80 | 81 | function test_long_128() public view { 82 | if (add_array.length >= 128) { 83 | if (lengthChecking) { 84 | assert(false); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /echidna_parade/__main__.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os.path 3 | import multiprocessing 4 | import sys 5 | 6 | from echidna_parade.config import create_parade_config 7 | from echidna_parade.campaign import run_campaign 8 | 9 | 10 | def parse_args(): 11 | parser = argparse.ArgumentParser() 12 | parser.add_argument( 13 | "files", 14 | type=os.path.abspath, 15 | nargs="+", 16 | default=None, 17 | help="FILES argument for echidna-test", 18 | ) 19 | parser.add_argument( 20 | "--name", 21 | type=str, 22 | help="name for parade (directory where output files are placed)", 23 | ) 24 | parser.add_argument( 25 | "--resume", 26 | type=str, 27 | default=None, 28 | help="parade to resume (directory name with existing run)", 29 | ) 30 | parser.add_argument( 31 | "--contract", type=str, default=None, help="CONTRACT argument for echidna-test" 32 | ) 33 | parser.add_argument( 34 | "--config", 35 | type=argparse.FileType("r"), 36 | default=None, 37 | help="CONFIG argument for echidna-test", 38 | ) 39 | parser.add_argument( 40 | "--bases", 41 | type=argparse.FileType("r"), 42 | default=None, 43 | help="file containing a list of additional configuration files to randomly choose among for non-initial runs", 44 | ) 45 | parser.add_argument( 46 | "--ncores", 47 | type=int, 48 | default=multiprocessing.cpu_count(), 49 | help="Number of cores to use (swarm instances to run in parallel (default = all available)", 50 | ) 51 | parser.add_argument( 52 | "--corpus_dir", 53 | type=os.path.abspath, 54 | default=None, 55 | help="Directory to store the echidna-parade corpus (useful when existing corpus available)", 56 | ) 57 | parser.add_argument( 58 | "--timeout", 59 | type=int, 60 | default=3600, 61 | help="Total testing time, use -1 for no timeout (default = 3600)", 62 | ) 63 | parser.add_argument( 64 | "--gen_time", 65 | type=int, 66 | default=300, 67 | help="Per-generation testing time (default = 300)", 68 | ) 69 | parser.add_argument( 70 | "--initial_time", 71 | type=int, 72 | default=300, 73 | help="Initial run testing time (default = 300)", 74 | ) 75 | parser.add_argument( 76 | "--seed", type=int, default=None, help="Random seed (default = None)." 77 | ) 78 | parser.add_argument( 79 | "--minseqLen", 80 | type=int, 81 | default=10, 82 | help="Minimum sequence length to use (default = 10).", 83 | ) 84 | parser.add_argument( 85 | "--maxseqLen", 86 | type=int, 87 | default=300, 88 | help="Maximum sequence length to use (default = 300).", 89 | ) 90 | parser.add_argument( 91 | "--PdefaultLen", 92 | type=float, 93 | default=0.5, 94 | help="Probability of using default/base length (default = 0.5)", 95 | ) 96 | parser.add_argument( 97 | "--PdefaultDict", 98 | type=float, 99 | default=0.5, 100 | help="Probability of using default/base dictionary usage frequency (default = 0.5)", 101 | ) 102 | parser.add_argument( 103 | "--prob", 104 | type=float, 105 | default=0.5, 106 | help="Probability of including functions in swarm config (default = 0.5).", 107 | ) 108 | parser.add_argument( 109 | "--always", 110 | type=str, 111 | nargs="+", 112 | default=[], 113 | help="functions to ALWAYS include in swarm configurations", 114 | ) 115 | parser.add_argument( 116 | "--no-slither", 117 | action="store_true", 118 | help="Do not run Slither (mostly for Vyper contracts, which Slither cannot handle).", 119 | ) 120 | parser.add_argument( 121 | "--functions", 122 | type=str, 123 | nargs="+", 124 | default=[], 125 | help="Alternative way to specify ABI for functions, when Slither cannot be used.", 126 | ) 127 | parser.add_argument( 128 | "--no-wait", 129 | action="store_true", 130 | help="Kill echidna subprocesses if they do not finish on time. Useful for a fair benchmarking.", 131 | ) 132 | parser.add_argument( 133 | "--clean-results", 134 | action="store_true", 135 | help="Delete the compilation and coverage files for each swarm instance when it completes." 136 | ) 137 | 138 | parsed_args = parser.parse_args(sys.argv[1:]) 139 | return (parsed_args, parser) 140 | 141 | 142 | def main(): 143 | parsed_args, parser = parse_args() 144 | config = create_parade_config(parsed_args, parser) 145 | run_campaign(config) 146 | 147 | 148 | if __name__ == "__main__": 149 | main() 150 | -------------------------------------------------------------------------------- /echidna_parade/echidna.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | from glob import glob 4 | from shutil import copy 5 | from subprocess import Popen 6 | from yaml import safe_load, dump 7 | from random import choice, randrange 8 | 9 | 10 | def create_base_echidna_config(config): 11 | base_config = {} 12 | if config.config is not None: 13 | y = safe_load(config.config) 14 | for key in y: 15 | if key not in [ 16 | "timeout", 17 | "testLimit", 18 | "stopOnFail", 19 | "corpusDir", 20 | "coverage", 21 | ]: 22 | base_config[key] = y[key] 23 | base_config["timeout"] = config.gen_time 24 | base_config["testLimit"] = 1000000000 # basically infinite, use timeout to control 25 | if "seqLen" not in base_config: 26 | base_config["seqLen"] = min(max(config.minseqLen, 100), config.maxseqLen) 27 | if "dictFreq" not in base_config: 28 | base_config["dictFreq"] = 0.40 29 | if config.corpus_dir is not None: 30 | base_config["corpusDir"] = config.corpus_dir 31 | else: 32 | if config.resume is None: 33 | base_config["corpusDir"] = os.path.abspath(config.name + "/corpus") 34 | else: 35 | base_config["corpusDir"] = os.path.abspath(config.resume + "/corpus") 36 | base_config["stopOnFail"] = False 37 | base_config["coverage"] = True 38 | return base_config 39 | 40 | 41 | def generate_echidna_config( 42 | rng, public, basic, bases, config, prefix=None, initial=False, coverage=False 43 | ): 44 | new_config = dict(basic) 45 | new_config["filterFunctions"] = [] 46 | new_config["filterBlacklist"] = True 47 | if initial: 48 | new_config["timeout"] = config.initial_time 49 | if coverage: 50 | new_config["timeout"] = 360000 51 | corpus_count = len(glob(new_config["corpusDir"] + "/coverage/*.txt")) 52 | new_config["testLimit"] = corpus_count * config.maxseqLen 53 | basic_list = [] 54 | blacklist = True 55 | if "filterFunctions" in basic: 56 | basic_list = basic["filterFunctions"] 57 | if "filterBlacklist" in basic: 58 | if not basic["filterBlacklist"]: 59 | blacklist = False 60 | excluded = [] 61 | for f in public: 62 | if blacklist: 63 | if f in config.always: 64 | continue 65 | if f in basic_list: 66 | excluded.append(f) 67 | elif (not (initial or coverage)) and (rng.random() > config.prob): 68 | excluded.append(f) 69 | else: 70 | if f in config.always: 71 | continue 72 | if f in basic_list: 73 | if (not (initial or coverage)) and (rng.random() <= config.prob): 74 | excluded.append(f) 75 | else: 76 | excluded.append(f) 77 | if (len(excluded) == len(public)) and (len(public) > 0): 78 | # This should be quite rare unless you have very few functions or a very low config.prob! 79 | print("Degenerate blacklist configuration, trying again...") 80 | return generate_echidna_config( 81 | rng, public, basic, bases, config, prefix, initial, coverage 82 | ) 83 | new_config["filterFunctions"] = excluded 84 | if not (initial or coverage): 85 | new_config["corpusDir"] = "corpus" 86 | new_config["mutConsts"] = [] 87 | for i in range(4): 88 | # The below is pretty ad-hoc, you can uses bases to over-ride 89 | new_config["mutConsts"].append(choice([0, 1, 2, 3, 1000, 2000])) 90 | if rng.random() < config.PdefaultLen: 91 | new_config["seqLen"] = randrange(config.minseqLen, config.maxseqLen) 92 | if rng.random() < config.PdefaultDict: 93 | new_config["dictFreq"] = randrange(5, 95) / 100.0 94 | if bases: 95 | base = rng.choose(bases) 96 | for k in base: 97 | new_config[k] = base[k] 98 | 99 | return new_config 100 | 101 | 102 | def create_echidna_process( 103 | prefix, 104 | rng, 105 | public_functions, 106 | base_config, 107 | bases, 108 | config, 109 | initial=False, 110 | coverage=False, 111 | ): 112 | g = generate_echidna_config( 113 | rng, 114 | public_functions, 115 | base_config, 116 | bases, 117 | config, 118 | prefix=prefix, 119 | initial=initial, 120 | coverage=coverage, 121 | ) 122 | print( 123 | "- LAUNCHING echidna-test in", 124 | prefix, 125 | "blacklisting [", 126 | ", ".join(g["filterFunctions"]), 127 | "] with seqLen", 128 | g["seqLen"], 129 | "dictFreq", 130 | g["dictFreq"], 131 | "and mutConsts ", 132 | g.setdefault("mutConsts", [1, 1, 1, 1]), 133 | ) 134 | try: 135 | os.mkdir(prefix) 136 | except OSError: 137 | pass 138 | if not (initial or coverage): 139 | os.mkdir(prefix + "/corpus") 140 | os.mkdir(prefix + "/corpus/coverage") 141 | for f in glob(base_config["corpusDir"] + "/coverage/*.txt"): 142 | copy(f, prefix + "/corpus/coverage/") 143 | with open(prefix + "/config.yaml", "w") as yf: 144 | yf.write(dump(g)) 145 | outf = open(prefix + "/echidna.out", "w") 146 | call = ["echidna-test"] 147 | call.extend(config.files) 148 | call.extend(["--config", "config.yaml"]) 149 | if config.contract is not None: 150 | call.extend(["--contract", config.contract]) 151 | call.extend(["--format", "text"]) 152 | return ( 153 | prefix, 154 | Popen(call, stdout=outf, stderr=outf, cwd=os.path.abspath(prefix)), 155 | outf, 156 | ) 157 | 158 | 159 | def detect_echidna_fail(failed_props, prefix): 160 | with open(prefix + "/echidna.out", "r") as ffile: 161 | for line in ffile: 162 | if "failed" in line[:-1]: 163 | if line[:-1] not in failed_props: 164 | print("NEW FAILURE:", line[:-1]) 165 | failed_props[line[:-1]] = [prefix] 166 | else: 167 | failed_props[line[:-1]].append(prefix) 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Echidna-Parade: A Tool for Diverse Multicore Smart Contract Fuzzing 2 | 3 | Echidna-parade is an experimental Python tool that uses configuration variance and a common corpus to try to throughly test smart contracts with the [Echidna smart-contract fuzzer](https://github.com/crytic/echidna). 4 | 5 | Echidna-parade is based on the original [code developed by Alex Groce at Northern Arizona University](https://github.com/agroce/echidna-parade/). 6 | 7 | ## Features 8 | 9 | * Scale smart contract fuzzing using as many Echidna processes as you can run in your computer 10 | * Start, stop or resume large fuzzing campaigns 11 | * Leverage [swarm testing](https://agroce.github.io/issta12.pdf) and [transaction-length variation](https://agroce.github.io/ase08.pdf) to trigger deep corners of the contracts under testing 12 | * Automatic collection and handling of corpus across all the Echidna processes. 13 | 14 | ## Usage 15 | 16 | ## Before starting 17 | 18 | Take a look to the [Echidna README](https://github.com/crytic/echidna#echidna-a-fast-smart-contract-fuzzer-) to make sure you know how use. We also recommend to check our [Building Secure Smart Contracts](https://github.com/crytic/building-secure-contracts) repository contains a crash course on Echidna, including examples, lessons and exercises. You should [start here](https://github.com/crytic/building-secure-contracts/tree/master/program-analysis/echidna#echidna-tutorial). 19 | 20 | ### Example 21 | 22 | This repository contains a [small smart contract](examples/justlen.sol) to test echidna-parade: 23 | 24 | ``` 25 | $ echidna-parade examples/justlen.sol --config examples/justlen.yaml --contract TEST --timeout 120 --gen_time 30 --ncores 8 --always "TEST.turn_on_length_checking()" "TEST.push_1()" "TEST.plus5()" "TEST.test_long_64()" "TEST.test_long_128()" 26 | Starting echidna-parade with config=Config(files=['/Users/adg326/echidna-parade/examples/justlen.sol'], name='parade.82538', contract='TEST', config=<_io.TextIOWrapper name='config.yaml' mode='r' encoding='UTF-8'>, ncores=8, corpus_dir=None, timeout=120, gen_time=30, seed=None, minseqLen=10, maxseqLen=300, prob=0.5, always=['turn_on_length_checking', 'push_1', 'plus5', 'test_long_64', 'test_long_128']) 27 | 28 | Results will be written to: /Users/adg326/echidna-parade/examples/parade.82538 29 | Identified 14 public functions: push_1, pop_1, double, plus5, halve, decimate, empty1, empty2, empty3, turn_on_length_checking, turn_off_length_checking, test_long_8, test_long_64, test_long_128 30 | 31 | RUNNING INITIAL CORPUS GENERATION 32 | - LAUNCHING echidna-test in parade.82538/initial blacklisting [ ] with seqLen 100 33 | parade.82538/initial FAILED 34 | NEW FAILURE: assertion in test_long_8: failed!💥 35 | 36 | SWARM GENERATION #1: ELAPSED TIME 38.62 SECONDS / 120 37 | - LAUNCHING echidna-test in parade.82538/gen.1.0 blacklisting [ halve, decimate, empty3 ] with seqLen 100 38 | - LAUNCHING echidna-test in parade.82538/gen.1.1 blacklisting [ pop_1, halve, decimate, empty2, empty3, test_long_8 ] with seqLen 100 39 | - LAUNCHING echidna-test in parade.82538/gen.1.2 blacklisting [ pop_1, double, halve, decimate, empty1, empty2, empty3 ] with seqLen 239 40 | - LAUNCHING echidna-test in parade.82538/gen.1.3 blacklisting [ empty1, empty2, empty3, test_long_8 ] with seqLen 296 41 | - LAUNCHING echidna-test in parade.82538/gen.1.4 blacklisting [ double ] with seqLen 100 42 | - LAUNCHING echidna-test in parade.82538/gen.1.5 blacklisting [ empty1, turn_off_length_checking, test_long_8 ] with seqLen 208 43 | - LAUNCHING echidna-test in parade.82538/gen.1.6 blacklisting [ pop_1, decimate, empty2 ] with seqLen 100 44 | - LAUNCHING echidna-test in parade.82538/gen.1.7 blacklisting [ pop_1, double, halve, turn_off_length_checking, test_long_8 ] with seqLen 86 45 | parade.82538/gen.1.2 FAILED 46 | NEW FAILURE: assertion in test_long_64: failed!💥 47 | NEW FAILURE: assertion in test_long_128: failed!💥 48 | parade.82538/gen.1.0 FAILED 49 | parade.82538/gen.1.1 FAILED 50 | parade.82538/gen.1.4 FAILED 51 | parade.82538/gen.1.6 FAILED 52 | 53 | SWARM GENERATION #2: ELAPSED TIME 86.73 SECONDS / 120 54 | - LAUNCHING echidna-test in parade.82538/gen.2.0 blacklisting [ decimate, empty1, empty2, empty3 ] with seqLen 19 55 | - LAUNCHING echidna-test in parade.82538/gen.2.1 blacklisting [ pop_1, empty1, empty3, turn_off_length_checking, test_long_8 ] with seqLen 103 56 | - LAUNCHING echidna-test in parade.82538/gen.2.2 blacklisting [ halve, empty1, empty2, empty3, test_long_8 ] with seqLen 226 57 | - LAUNCHING echidna-test in parade.82538/gen.2.3 blacklisting [ halve, decimate, empty1, empty3 ] with seqLen 100 58 | - LAUNCHING echidna-test in parade.82538/gen.2.4 blacklisting [ pop_1, double, decimate, empty2, test_long_8 ] with seqLen 100 59 | - LAUNCHING echidna-test in parade.82538/gen.2.5 blacklisting [ double, empty1, turn_off_length_checking, test_long_8 ] with seqLen 20 60 | - LAUNCHING echidna-test in parade.82538/gen.2.6 blacklisting [ pop_1, halve, empty2, turn_off_length_checking, test_long_8 ] with seqLen 194 61 | - LAUNCHING echidna-test in parade.82538/gen.2.7 blacklisting [ halve, decimate, empty1, empty2, empty3, turn_off_length_checking ] with seqLen 100 62 | parade.82538/gen.2.4 FAILED 63 | parade.82538/gen.2.3 FAILED 64 | parade.82538/gen.2.7 FAILED 65 | parade.82538/gen.2.0 FAILED 66 | parade.82538/gen.2.1 FAILED 67 | parade.82538/gen.2.5 FAILED 68 | parade.82538/gen.2.2 FAILED 69 | parade.82538/gen.2.6 FAILED 70 | DONE! 71 | 72 | SOME TESTS FAILED 73 | 74 | Property results: 75 | ======================================== 76 | assertion in test_long_8: failed!💥 77 | FAILED 8 TIMES 78 | See: parade.82538/initial/echidna.out, parade.82538/gen.1.2/echidna.out, parade.82538/gen.1.0/echidna.out, parade.82538/gen.1.4/echidna.out, parade.82538/gen.1.6/echidna.out, parade.82538/gen.2.3/echidna.out, parade.82538/gen.2.7/echidna.out, parade.82538/gen.2.0/echidna.out 79 | ======================================== 80 | assertion in test_long_64: failed!💥 81 | FAILED 9 TIMES 82 | See: parade.82538/gen.1.2/echidna.out, parade.82538/gen.2.4/echidna.out, parade.82538/gen.2.3/echidna.out, parade.82538/gen.2.7/echidna.out, parade.82538/gen.2.0/echidna.out, parade.82538/gen.2.1/echidna.out, parade.82538/gen.2.5/echidna.out, parade.82538/gen.2.2/echidna.out, parade.82538/gen.2.6/echidna.out 83 | ======================================== 84 | assertion in test_long_128: failed!💥 85 | FAILED 11 TIMES 86 | See: parade.82538/gen.1.2/echidna.out, parade.82538/gen.1.0/echidna.out, parade.82538/gen.1.1/echidna.out, parade.82538/gen.2.4/echidna.out, parade.82538/gen.2.3/echidna.out, parade.82538/gen.2.7/echidna.out, parade.82538/gen.2.0/echidna.out, parade.82538/gen.2.1/echidna.out, parade.82538/gen.2.5/echidna.out, parade.82538/gen.2.2/echidna.out, parade.82538/gen.2.6/echidna.out 87 | ``` 88 | 89 | A more detailed explanation on how to perform smart contract fuzzing at scale using echidna-parade is available [here](https://github.com/crytic/building-secure-contracts/blob/master/program-analysis/echidna/smart-contract-fuzzing-at-scale.md). 90 | 91 | ## Installation 92 | 93 | Before starting, make sure Echidna is [installed](https://github.com/crytic/echidna#installation). Then, just use pip to install echidna-parade: 94 | 95 | 96 | ``` 97 | $ pip3 install echidna-parade 98 | ``` 99 | 100 | or from this repository: 101 | 102 | ``` 103 | $ git clone https://github.com/crytic/echidna-parade 104 | $ cd echidna-parade 105 | $ pip3 install . --user 106 | ``` 107 | 108 | ## Getting help 109 | 110 | Feel free to stop by our #ethereum slack channel in [Empire Hacking](https://empireslacking.herokuapp.com/) for help using or extending echidna-parade. 111 | Also, considering [emailing](mailto:echidna-dev@trailofbits.com) the Echidna development team directly for more detailed questions 112 | 113 | ## License 114 | 115 | Echidna-parade is licensed and distributed under the [AGPLv3 license](https://github.com/crytic/echidna-parade/blob/main/LICENSE). 116 | 117 | ## Publications 118 | 119 | ### Trail of Bits 120 | - [echidna-parade: A Tool for Diverse Multicore Smart Contract Fuzzing](https://agroce.github.io/issta21.pdf), Alex Groce, Gustavo Grieco- ISSTA '21 121 | -------------------------------------------------------------------------------- /echidna_parade/campaign.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os.path 3 | 4 | from glob import glob 5 | from shutil import copy, rmtree 6 | from slither import Slither 7 | from sys import exit 8 | from random import Random 9 | from yaml import safe_load 10 | 11 | from echidna_parade.echidna import ( 12 | create_base_echidna_config, 13 | generate_echidna_config, 14 | create_echidna_process, 15 | detect_echidna_fail, 16 | ) 17 | 18 | 19 | def get_callable_functions(config, base_config): 20 | 21 | prop_prefix = "echidna_" 22 | if "prefix" in base_config: 23 | prop_prefix = base_config["prefix"] 24 | 25 | public_functions = [] 26 | for f in config.files: 27 | if not os.path.exists(f): 28 | raise ValueError("Specified file " + f + " does not exist!") 29 | if not config.no_slither: 30 | slither = Slither(f) 31 | for contract in slither.contracts: 32 | if "multi-abi" not in base_config or not base_config["multi-abi"]: 33 | if ( 34 | config.contract is not None 35 | ): # if you don't tell us which contract, no pruning 36 | if contract.name != config.contract: 37 | continue 38 | for function in contract.functions_entry_points: 39 | if not function.is_implemented: 40 | continue 41 | fname = function.full_name 42 | if function.is_constructor or (fname.find(prop_prefix) == 0): 43 | # Don't bother blacklisting constructors or echidna properties 44 | continue 45 | if function.visibility in ["public", "external"]: 46 | public_functions.append(contract.name + "." + fname) 47 | return public_functions 48 | 49 | 50 | def clean_results(pname): 51 | "Delete the compilation and coverage data from a swarm instance's working directory" 52 | rmtree(pname + "/crytic-export", ignore_errors=True) 53 | rmtree(pname + "/corpus", ignore_errors=True) 54 | 55 | def run_campaign(config): 56 | print("Starting echidna-parade with config={}".format(config)) 57 | 58 | if config.resume is None: 59 | if os.path.exists(config.name): 60 | raise ValueError( 61 | config.name 62 | + ": refusing to overwrite existing directory; perhaps you meant to --resume?" 63 | ) 64 | else: 65 | os.mkdir(config.name) 66 | 67 | print() 68 | print("Results will be written to:", os.path.abspath(config.name)) 69 | else: 70 | print("Attempting to resume testing from", config.resume) 71 | if not os.path.exists(config.resume): 72 | raise ValueError("No parade directory found!") 73 | if not (os.path.exists(config.resume + "/initial")): 74 | raise ValueError( 75 | "No initial run present, does not look like a parade directory!" 76 | ) 77 | 78 | rng = Random(config.seed) 79 | 80 | base_config = create_base_echidna_config(config) 81 | if not os.path.exists(base_config["corpusDir"]): 82 | os.mkdir(base_config["corpusDir"]) 83 | 84 | print(base_config) 85 | 86 | bases = [] 87 | if config.bases is not None: 88 | with open(config.bases, "r") as bfile: 89 | for line in bfile: 90 | base = line[:-1] 91 | y = safe_load(base) 92 | bases.append(y) 93 | 94 | public_functions = get_callable_functions(config, base_config) 95 | public_functions.extend(config.functions) 96 | 97 | print( 98 | "Identified", 99 | len(public_functions), 100 | "public and external functions:", 101 | ", ".join(public_functions), 102 | ) 103 | if len(public_functions) == 0: 104 | print( 105 | "WARNING: something may be wrong; no public or external functions were found!" 106 | ) 107 | print() 108 | 109 | print(public_functions) 110 | failures = [] 111 | failed_props = {} 112 | start = time.time() 113 | elapsed = time.time() - start 114 | 115 | if config.resume is None: 116 | print() 117 | print("RUNNING INITIAL CORPUS GENERATION") 118 | prefix = config.name + "/initial" 119 | (pname, p, outf) = create_echidna_process( 120 | prefix, rng, public_functions, base_config, bases, config, initial=True 121 | ) 122 | p.wait() 123 | outf.close() 124 | if p.returncode != 0: 125 | print(pname, "FAILED") 126 | detect_echidna_fail(failed_props, pname) 127 | failures.append(pname + "/echidna.out") 128 | 129 | generation = 1 130 | if config.resume is None: 131 | run_name = config.name 132 | else: 133 | run_name = config.resume 134 | generation = 1 135 | while os.path.exists(run_name + "/gen." + str(generation) + ".0"): 136 | generation += 1 137 | print("RESUMING PARADE AT GENERATION", generation) 138 | 139 | elapsed = time.time() - start 140 | while (config.timeout == -1) or (elapsed < config.timeout): 141 | print() 142 | print( 143 | "SWARM GENERATION #" + str(generation) + ": ELAPSED TIME", 144 | round(elapsed, 2), 145 | "SECONDS", 146 | ("/ " + str(config.timeout)) if config.timeout != -1 else "", 147 | ) 148 | ps = [] 149 | for i in range(config.ncores): 150 | prefix = run_name + "/gen." + str(generation) + "." + str(i) 151 | ps.append( 152 | create_echidna_process( 153 | prefix, rng, public_functions, base_config, bases, config 154 | ) 155 | ) 156 | any_not_done = True 157 | gen_start = time.time() 158 | while any_not_done: 159 | any_not_done = False 160 | done = [] 161 | for (pname, p, outf) in ps: 162 | if p.poll() is None: 163 | any_not_done = True 164 | else: 165 | done.append((pname, p, outf)) 166 | outf.close() 167 | for f in glob(pname + "/corpus/coverage/*.txt"): 168 | if not os.path.exists( 169 | base_config["corpusDir"] 170 | + "/coverage/" 171 | + os.path.basename(f) 172 | ): 173 | print("COLLECTING NEW COVERAGE:", f) 174 | copy(f, base_config["corpusDir"] + "/coverage") 175 | if p.returncode != 0: 176 | print(pname, "FAILED") 177 | detect_echidna_fail(failed_props, pname) 178 | failures.append(pname + "/echidna.out") 179 | if config.clean_results: 180 | clean_results(pname) 181 | for d in done: 182 | ps.remove(d) 183 | gen_elapsed = time.time() - gen_start 184 | if (config.no_wait) and ( 185 | gen_elapsed > (config.gen_time + 60) 186 | ): # full 60 second fudge factor here! 187 | print("Generation still running after timeout! Killing echidna...") 188 | for (pname, p, outf) in ps: 189 | outf.close() 190 | for f in glob(pname + "/corpus/coverage/*.txt"): 191 | if not os.path.exists( 192 | base_config["corpusDir"] 193 | + "/coverage/" 194 | + os.path.basename(f) 195 | ): 196 | print("COLLECTING NEW COVERAGE:", f) 197 | copy(f, base_config["corpusDir"] + "/coverage") 198 | if config.clean_results: 199 | clean_results(pname) 200 | if p.poll() is None: 201 | p.kill() 202 | any_not_done = False 203 | elapsed = time.time() - start 204 | generation += 1 205 | print("DONE!") 206 | print("RUNNING FINAL COVERAGE PASS...") 207 | try: 208 | os.remove(glob(base_config["corpusDir"] + "/covered.*.txt")[0]) 209 | except IndexError: 210 | pass 211 | start = time.time() 212 | if config.resume is None: 213 | prefix = config.name + "/coverage" 214 | else: 215 | prefix = config.resume + "/coverage" 216 | (pname, p, outf) = create_echidna_process( 217 | prefix, 218 | rng, 219 | public_functions, 220 | base_config, 221 | bases, 222 | config, 223 | initial=True, 224 | coverage=True, 225 | ) 226 | p.wait() 227 | outf.close() 228 | if p.returncode != 0: 229 | print(pname, "FAILED") 230 | detect_echidna_fail(failed_props, pname) 231 | failures.append(pname + "/echidna.out") 232 | print("COVERAGE PASS TOOK", round(time.time() - start, 2), "SECONDS") 233 | print() 234 | if len(failures) == 0: 235 | print("NO FAILURES") 236 | exit(0) 237 | else: 238 | print("SOME TESTS FAILED") 239 | print() 240 | print("Property results:") 241 | for prop in sorted(failed_props.keys(), key=lambda x: len(failed_props[x])): 242 | print("=" * 40) 243 | print(prop) 244 | print("FAILED", len(failed_props[prop]), "TIMES") 245 | print( 246 | "See:", ", ".join(map(lambda p: p + "/echidna.out", failed_props[prop])) 247 | ) 248 | 249 | exit(len(failures)) 250 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | --------------------------------------------------------------------------------