Contributing

Help is always appreciated!

To get started, you can try Building from Source in order to familiarize yourself with the components of Solidity and the build process. Also, it may be useful to become well-versed at writing smart-contracts in Solidity.

In particular, we need help in the following areas:

Please note that this project is released with a Contributor Code of Conduct. By participating in this project - in the issues, pull requests, or Gitter channels - you agree to abide by its terms.

Team Calls

If you have issues or pull requests to discuss, or are interested in hearing what the team and contributors are working on, you can join our public team calls:

  • Monday at 12pm CET
  • Wednesday at 3pm CET

Both calls take place on Google Hangouts.

How to Report Issues

To report an issue, please use the GitHub issues tracker. When reporting issues, please mention the following details:

  • Which version of Solidity you are using
  • What was the source code (if applicable)
  • Which platform are you running on
  • How to reproduce the issue
  • What was the result of the issue
  • What the expected behaviour is

Reducing the source code that caused the issue to a bare minimum is always very helpful and sometimes even clarifies a misunderstanding.

Workflow for Pull Requests

In order to contribute, please fork off of the develop branch and make your changes there. Your commit messages should detail why you made your change in addition to what you did (unless it is a tiny change).

If you need to pull in any changes from develop after making your fork (for example, to resolve potential merge conflicts), please avoid using git merge and instead, git rebase your branch. This will help us review your change more easily.

Additionally, if you are writing a new feature, please ensure you add appropriate test cases under test/ (see below).

However, if you are making a larger change, please consult with the Solidity Development Gitter channel (different from the one mentioned above, this one is focused on compiler and language development instead of language use) first.

New features and bugfixes should be added to the Changelog.md file: please follow the style of previous entries, when applicable.

Finally, please make sure you respect the coding style for this project. Also, even though we do CI testing, please test your code and ensure that it builds locally before submitting a pull request.

Thank you for your help!

Running the compiler tests

The ./scripts/tests.sh script executes most Solidity tests automatically, but for quicker feedback, you might want to run specific tests.

Solidity includes different types of tests, most of them bundled into the Boost C++ Test Framework application soltest. Running build/test/soltest` or its wrapper ``scripts/soltest.sh is sufficient for most changes.

Some tests require the libevmone.so library, others require libz3.

The test system will automatically try to discover the location of libevmone.so starting from the current directory. If it does not find it, the relevant tests are skipped. To run all tests, download the library from Github and either place it in the project root path or inside the deps folder.

If you do not have libz3 installed on your system, you should disable the SMT tests: ./scripts/soltest.sh --no-smt.

./build/test/soltest --help has extensive help on all of the options available. See especially:

Note

Those working in a Windows environment wanting to run the above basic sets without libz3 in Git Bash, you would have to do: ./build/test/Release/soltest.exe -- --no-smt. If you are running this in plain Command Prompt, use .\build\test\Release\soltest.exe -- --no-smt.

To run a subset of tests, you can use filters: ./scripts/soltest.sh -t TestSuite/TestName, where ``TestName can be a wildcard *.

For example, here is an example test you might run; ./scripts/soltest.sh -t "yulOptimizerTests/disambiguator/*" --no-smt. This will test all the tests for the disambiguator.

To get a list of all tests, use ./build/test/soltest --list_content=HRF.

If you want to debug using GDB, make sure you build differently than the “usual”. For example, you could run the following command in your build folder:

cmake -DCMAKE_BUILD_TYPE=Debug ..
make

This will create symbols such that when you debug a test using the --debug flag, you will have access to functions and variables in which you can break or print with.

The script ./scripts/tests.sh also runs commandline tests and compilation tests in addition to those found in soltest.

The CI runs additional tests (including solc-js and testing third party Solidity frameworks) that require compiling the Emscripten target.

Writing and running syntax tests

Syntax tests check that the compiler generates the correct error messages for invalid code and properly accepts valid code. They are stored in individual files inside the tests/libsolidity/syntaxTests folder. These files must contain annotations, stating the expected result(s) of the respective test. The test suite compiles and checks them against the given expectations.

For example: ./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol

contract test {
    uint256 variable;
    uint128 variable;
}
// ----
// DeclarationError: (36-52): Identifier already declared.

A syntax test must contain at least the contract under test itself, followed by the separator // ----. The comments that follow the separator are used to describe the expected compiler errors or warnings. The number range denotes the location in the source where the error occurred. If you want the contract to compile without any errors or warning you can leave out the separator and the comments that follow it.

In the above example, the state variable variable was declared twice, which is not allowed. This results in a DeclarationError stating that the identifier was already declared.

The isoltest tool is used for these tests and you can find it under ./build/test/tools/. It is an interactive tool which allows editing of failing contracts using your preferred text editor. Let’s try to break this test by removing the second declaration of variable:

contract test {
    uint256 variable;
}
// ----
// DeclarationError: (36-52): Identifier already declared.

Running ./build/test/isoltest again results in a test failure:

syntaxTests/double_stateVariable_declaration.sol: FAIL
    Contract:
        contract test {
            uint256 variable;
        }

    Expected result:
        DeclarationError: (36-52): Identifier already declared.
    Obtained result:
        Success

isoltest prints the expected result next to the obtained result, and also provides a way to edit, update or skip the current contract file, or quit the application.

It offers several options for failing tests:

  • edit: isoltest tries to open the contract in an editor so you can adjust it. It either uses the editor given on the command line (as isoltest --editor /path/to/editor), in the environment variable EDITOR or just /usr/bin/editor (in that order).
  • update: Updates the expectations for contract under test. This updates the annotations by removing unmet expectations and adding missing expectations. The test is then run again.
  • skip: Skips the execution of this particular test.
  • quit: Quits isoltest.

All of these options apply to the current contract, expect quit which stops the entire testing process.

Automatically updating the test above changes it to

contract test {
    uint256 variable;
}
// ----

and re-run the test. It now passes again:

Re-running test case...
syntaxTests/double_stateVariable_declaration.sol: OK

Note

Choose a name for the contract file that explains what it tests, e.g. double_variable_declaration.sol. Do not put more than one contract into a single file, unless you are testing inheritance or cross-contract calls. Each file should test one aspect of your new feature.

Running the Fuzzer via AFL

Fuzzing is a technique that runs programs on more or less random inputs to find exceptional execution states (segmentation faults, exceptions, etc). Modern fuzzers are clever and run a directed search inside the input. We have a specialized binary called solfuzzer which takes source code as input and fails whenever it encounters an internal compiler error, segmentation fault or similar, but does not fail if e.g., the code contains an error. This way, fuzzing tools can find internal problems in the compiler.

We mainly use AFL for fuzzing. You need to download and install the AFL packages from your repositories (afl, afl-clang) or build them manually. Next, build Solidity (or just the solfuzzer binary) with AFL as your compiler:

cd build
# if needed
make clean
cmake .. -DCMAKE_C_COMPILER=path/to/afl-gcc -DCMAKE_CXX_COMPILER=path/to/afl-g++
make solfuzzer

At this stage you should be able to see a message similar to the following:

Scanning dependencies of target solfuzzer
[ 98%] Building CXX object test/tools/CMakeFiles/solfuzzer.dir/fuzzer.cpp.o
afl-cc 2.52b by <lcamtuf@google.com>
afl-as 2.52b by <lcamtuf@google.com>
[+] Instrumented 1949 locations (64-bit, non-hardened mode, ratio 100%).
[100%] Linking CXX executable solfuzzer

If the instrumentation messages did not appear, try switching the cmake flags pointing to AFL’s clang binaries:

# if previously failed
make clean
cmake .. -DCMAKE_C_COMPILER=path/to/afl-clang -DCMAKE_CXX_COMPILER=path/to/afl-clang++
make solfuzzer

Otherwise, upon execution the fuzzer halts with an error saying binary is not instrumented:

afl-fuzz 2.52b by <lcamtuf@google.com>
... (truncated messages)
[*] Validating target binary...

[-] Looks like the target binary is not instrumented! The fuzzer depends on
    compile-time instrumentation to isolate interesting test cases while
    mutating the input data. For more information, and for tips on how to
    instrument binaries, please see /usr/share/doc/afl-doc/docs/README.

    When source code is not available, you may be able to leverage QEMU
    mode support. Consult the README for tips on how to enable this.
    (It is also possible to use afl-fuzz as a traditional, "dumb" fuzzer.
    For that, you can use the -n option - but expect much worse results.)

[-] PROGRAM ABORT : No instrumentation detected
         Location : check_binary(), afl-fuzz.c:6920

Next, you need some example source files. This makes it much easier for the fuzzer to find errors. You can either copy some files from the syntax tests or extract test files from the documentation or the other tests:

mkdir /tmp/test_cases
cd /tmp/test_cases
# extract from tests:
path/to/solidity/scripts/isolate_tests.py path/to/solidity/test/libsolidity/SolidityEndToEndTest.cpp
# extract from documentation:
path/to/solidity/scripts/isolate_tests.py path/to/solidity/docs docs

The AFL documentation states that the corpus (the initial input files) should not be too large. The files themselves should not be larger than 1 kB and there should be at most one input file per functionality, so better start with a small number of. There is also a tool called afl-cmin that can trim input files that result in similar behaviour of the binary.

Now run the fuzzer (the -m extends the size of memory to 60 MB):

afl-fuzz -m 60 -i /tmp/test_cases -o /tmp/fuzzer_reports -- /path/to/solfuzzer

The fuzzer creates source files that lead to failures in /tmp/fuzzer_reports. Often it finds many similar source files that produce the same error. You can use the tool scripts/uniqueErrors.sh to filter out the unique errors.

Whiskers

Whiskers is a string templating system similar to Mustache. It is used by the compiler in various places to aid readability, and thus maintainability and verifiability, of the code.

The syntax comes with a substantial difference to Mustache. The template markers {{ and }} are replaced by < and > in order to aid parsing and avoid conflicts with Inline Assembly (The symbols < and > are invalid in inline assembly, while { and } are used to delimit blocks). Another limitation is that lists are only resolved one depth and they do not recurse. This may change in the future.

A rough specification is the following:

Any occurrence of <name> is replaced by the string-value of the supplied variable name without any escaping and without iterated replacements. An area can be delimited by <#name>...</name>. It is replaced by as many concatenations of its contents as there were sets of variables supplied to the template system, each time replacing any <inner> items by their respective value. Top-level variables can also be used inside such areas.

Documentation Style Guide

The following are style recommendations specifically for documentation contributions to Solidity.

English Language

Use English, with British English spelling preferred, unless using project or brand names. Try to reduce the usage of local slang and references, making your language as clear to all readers as possible. Below are some references to help:

Note

While the official Solidity documentation is written in English, there are community contributed Translations in other languages available.

Title Case for Headings

Use title case for headings. This means capitalise all principal words in titles, but not articles, conjunctions, and prepositions unless they start the title.

For example, the following are all correct:

  • Title Case for Headings
  • For Headings Use Title Case
  • Local and State Variable Names
  • Order of Layout

Expand Contractions

Use expanded contractions for words, for example:

  • “Do not” instead of “Don’t”.
  • “Can not” instead of “Can’t”.

Active and Passive Voice

Active voice is typically recommended for tutorial style documentation as it helps the reader understand who or what is performing a task. However, as the Solidity documentation is a mixture of tutorials and reference content, passive voice is sometimes more applicable.

As a summary:

  • Use passive voice for technical reference, for example language definition and internals of the Ethereum VM.
  • Use active voice when describing recommendations on how to apply an aspect of Solidity.

For example, the below is in passive voice as it specifies an aspect of Solidity:

Functions can be declared pure in which case they promise not to read from or modify the state.

For example, the below is in active voice as it discusses an application of Solidity:

When invoking the compiler, you can specify how to discover the first element of a path, and also path prefix remappings.

Common Terms

  • “Function parameters” and “return variables”, not input and output parameters.

Code Examples

A CI process tests all code block formatted code examples that begin with pragma solidity, contract, library or interface using the ./test/cmdlineTests.sh script when you create a PR. If you are adding new code examples, ensure they work and pass tests before creating the PR.

Ensure that all code examples begin with a pragma version that spans the largest where the contract code is valid. For example pragma solidity >=0.4.0 <0.7.0;.

Running Documentation Tests

Make sure your contributions pass our documentation tests by running ./scripts/docs.sh that installs dependencies needed for documentation and checks for any problems such as broken links or syntax issues.