diff options
52 files changed, 1337 insertions, 809 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 196cbb32..0cc0edec 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,12 +6,12 @@ about: Bug reports about the Solidity Compiler. ## Prerequisites - First, many thanks for taking part in the community. We really appreciate that. -- We realize there is a lot of data requested here. We ask only that you do your best to provide as much information as possible so we can better help you. +- We realize there is a lot of information requested here. We ask only that you do your best to provide as much information as possible so we can better help you. - Support questions are better asked in one of the following locations: - [Solidity chat](https://gitter.im/ethereum/solidity) - [Stack Overflow](https://ethereum.stackexchange.com/) - Ensure the issue isn't already reported. -- The issue should be reproducible with the latest solidity version , however, this isn't a hard requirement and being reproducible with an older version is sufficient. +- The issue should be reproducible with the latest solidity version; however, this isn't a hard requirement and being reproducible with an older version is sufficient. *Delete the above section and the instructions in the sections below before submitting* diff --git a/.travis.yml b/.travis.yml index 8487deef..ef4f8b39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -184,7 +184,7 @@ deploy: # Both the build and deploy steps for Emscripten are only run within the Ubuntu # configurations (not for macOS). That is controlled by conditionals within the bash # scripts because TravisCI doesn't provide much in the way of conditional logic. - + - provider: script script: test $SOLC_EMSCRIPTEN != On || (scripts/release_emscripten.sh) skip_cleanup: true diff --git a/CODING_STYLE.md b/CODING_STYLE.md index f36503d0..8101db0c 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -193,7 +193,7 @@ for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); 2. Generally avoid shortening a standard form that already includes all important information: - e.g. stick to `shared_ptr<X>` rather than shortening to `ptr<X>`. 3. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently: - - e.g. `using Guard = std::lock_guard<std::mutex>;` ///< Guard is used throughout the codebase since it is clear in meaning and used commonly. + - e.g. `using Guard = std::lock_guard<std::mutex>;` ///< Guard is used throughout the codebase since it is clear in meaning and used commonly. 4. In general expressions should be roughly as important/semantically meaningful as the space they occupy. 5. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time. diff --git a/Changelog.md b/Changelog.md index 177a071b..1e16df59 100644 --- a/Changelog.md +++ b/Changelog.md @@ -71,6 +71,7 @@ Breaking Changes: * View Pure Checker: Strictly enfore state mutability. This was already the case in the experimental 0.5.0 mode. Language Features: + * Genreal: Add ``staticcall`` to ``address``. * General: Allow appending ``calldata`` keyword to types, to explicitly specify data location for arguments of external functions. * General: Support ``pop()`` for storage arrays. * General: Scoping rules now follow the C99-style. @@ -108,6 +109,8 @@ Bugfixes: * Type Checker: Fix crashes in erroneous tuple assignments in which the type of the right hand side cannot be determined. * Type Checker: Fix freeze for negative fixed-point literals very close to ``0``, such as ``-1e-100``. * Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values. + * Type Checker: Report error when using indexed structs in events with experimental ABIEncoderV2. This used to log wrong values. + * Type Checker: Dynamic types as key for public mappings return error instead of assertion fail. * Type System: Allow arbitrary exponents for literals with a mantissa of zero. ### 0.4.24 (2018-05-16) @@ -1,19 +1,64 @@ # The Solidity Contract-Oriented Programming Language [](https://gitter.im/ethereum/solidity?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://travis-ci.org/ethereum/solidity) +Solidity is a statically typed, contract-oriented, high-level language for implementing smart contracts on the Ethereum platform. -## Useful links -To get started you can find an introduction to the language in the [Solidity documentation](https://solidity.readthedocs.org). In the documentation, you can find [code examples](https://solidity.readthedocs.io/en/latest/solidity-by-example.html) as well as [a reference](https://solidity.readthedocs.io/en/latest/solidity-in-depth.html) of the syntax and details on how to write smart contracts. +## Table of Contents -You can start using [Solidity in your browser](http://remix.ethereum.org) with no need to download or compile anything. +- [Background](#background) +- [Build and Install](#build-and-install) +- [Example](#example) +- [Documentation](#documentation) +- [Development](#development) +- [Maintainers](#maintainers) +- [License](#license) -The changelog for this project can be found [here](https://github.com/ethereum/solidity/blob/develop/Changelog.md). +## Background -Solidity is still under development. So please do not hesitate and open an [issue in GitHub](https://github.com/ethereum/solidity/issues) if you encounter anything strange. +Solidity is a statically-typed curly-braces programming language designed for developing smart contracts +that run on the Ethereum Virtual Machine. Smart contracts are programs that are executed inside a peer-to-peer +network where nobody has special authority over the execution and thus they allow to implement tokens of value, +ownership, voting and other kinds of logics. -## Building -See the [Solidity documentation](https://solidity.readthedocs.io/en/latest/installing-solidity.html#building-from-source) for build instructions. +## Build and Install -## How to Contribute -Please see our [contribution guidelines](https://solidity.readthedocs.io/en/latest/contributing.html) in the Solidity documentation. +Instructions about how to build and install the Solidity compiler can be found in the [Solidity documentation](https://solidity.readthedocs.io/en/latest/installing-solidity.html#building-from-source) + + +## Example + +A "Hello World" program in Solidity is of even less use than in other languages, but still: + +``` +contract HelloWorld { + function f() pure returns (string memory) { + return "Hello, World!"; + } +} +``` + +To get started with Solidity, you can use [Remix](https://remix.ethereum.org/), which is an +browser-based IDE. Here are some example contracts: + +1. [Voting](https://solidity.readthedocs.io/en/v0.4.24/solidity-by-example.html#voting) +2. [Blind Auction](https://solidity.readthedocs.io/en/v0.4.24/solidity-by-example.html#blind-auction) +3. [Safe remote purchase](https://solidity.readthedocs.io/en/v0.4.24/solidity-by-example.html#safe-remote-purchase) +4. [Micropayment Channel](https://solidity.readthedocs.io/en/v0.4.24/solidity-by-example.html#micropayment-channel) + +## Documentation + +The Solidity documentation is hosted at [Read the docs](https://solidity.readthedocs.io). + +## Development + +Solidity is still under development. Contributions are always welcome! +Please follow the +[Developers Guide](https://solidity.readthedocs.io/en/latest/contributing.html) +if you want to help. + +## Maintainers +[@axic](https://github.com/axic) +[@chriseth](https://github.com/chriseth) + +## License +Solidity is licensed under [GNU General Public License v3.0](https://github.com/ethereum/solidity/blob/develop/LICENSE.txt) -Any contributions are welcome! diff --git a/cmake/scripts/buildinfo.cmake b/cmake/scripts/buildinfo.cmake index 9147a1b4..3fb6beb2 100644 --- a/cmake/scripts/buildinfo.cmake +++ b/cmake/scripts/buildinfo.cmake @@ -1,5 +1,5 @@ # generates BuildInfo.h -# +# # this module expects # ETH_SOURCE_DIR - main CMAKE_SOURCE_DIR # ETH_DST_DIR - main CMAKE_BINARY_DIR diff --git a/docs/bugs.json b/docs/bugs.json index 3f20077f..839ea128 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,5 +1,13 @@ [ { + "name": "EventStructWrongData", + "summary": "Using structs in events logged wrong data.", + "description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.", + "introduced": "0.4.17", + "fixed": "0.5.0", + "severity": "very low" + }, + { "name": "NestedArrayFunctionCallDecoder", "summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.", "description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index b400121f..ab200036 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1,555 +1,565 @@ { "0.1.0": { "bugs": [ - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-07-10" - }, + }, "0.1.1": { "bugs": [ - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-08-04" - }, + }, "0.1.2": { "bugs": [ - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-08-20" - }, + }, "0.1.3": { "bugs": [ - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-09-25" - }, + }, "0.1.4": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-09-30" - }, + }, "0.1.5": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-10-07" - }, + }, "0.1.6": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-10-16" - }, + }, "0.1.7": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-11-17" - }, + }, "0.2.0": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2015-12-02" - }, + }, "0.2.1": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2016-01-30" - }, + }, "0.2.2": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", - "ArrayAccessCleanHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", + "ArrayAccessCleanHigherOrderBits", "AncientCompiler" - ], + ], "released": "2016-02-17" - }, + }, "0.3.0": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", - "CleanBytesHigherOrderBits", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", + "CleanBytesHigherOrderBits", "ArrayAccessCleanHigherOrderBits" - ], + ], "released": "2016-03-11" - }, + }, "0.3.1": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", "CleanBytesHigherOrderBits" - ], + ], "released": "2016-03-31" - }, + }, "0.3.2": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", - "OptimizerClearStateOnCodePathJoin", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", + "OptimizerClearStateOnCodePathJoin", "CleanBytesHigherOrderBits" - ], + ], "released": "2016-04-18" - }, + }, "0.3.3": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", "OptimizerClearStateOnCodePathJoin" - ], + ], "released": "2016-05-27" - }, + }, "0.3.4": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", "OptimizerClearStateOnCodePathJoin" - ], + ], "released": "2016-05-31" - }, + }, "0.3.5": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", - "SendFailsForZeroEther", - "DynamicAllocationInfiniteLoop", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", + "SendFailsForZeroEther", + "DynamicAllocationInfiniteLoop", "OptimizerClearStateOnCodePathJoin" - ], + ], "released": "2016-06-10" - }, + }, "0.3.6": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", "SendFailsForZeroEther" - ], + ], "released": "2016-08-10" - }, + }, "0.4.0": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", "LibrariesNotCallableFromPayableFunctions" - ], + ], "released": "2016-09-08" - }, + }, "0.4.1": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", - "OptimizerStaleKnowledgeAboutSHA3", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", + "OptimizerStaleKnowledgeAboutSHA3", "LibrariesNotCallableFromPayableFunctions" - ], + ], "released": "2016-09-09" - }, + }, "0.4.10": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", "ConstantOptimizerSubtraction" - ], + ], "released": "2017-03-15" - }, + }, "0.4.11": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", "SkipEmptyStringLiteral" - ], + ], "released": "2017-05-03" - }, + }, "0.4.12": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", "ECRecoverMalformedInput" - ], + ], "released": "2017-07-03" - }, + }, "0.4.13": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", "ECRecoverMalformedInput" - ], + ], "released": "2017-07-06" - }, + }, "0.4.14": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", "DelegateCallReturnValue" - ], + ], "released": "2017-07-31" - }, + }, "0.4.15": { "bugs": [ - "NestedArrayFunctionCallDecoder", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" - ], + ], "released": "2017-08-08" - }, + }, "0.4.16": { "bugs": [ - "NestedArrayFunctionCallDecoder", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" - ], + ], "released": "2017-08-24" - }, + }, "0.4.17": { "bugs": [ - "NestedArrayFunctionCallDecoder", + "EventStructWrongData", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" - ], + ], "released": "2017-09-21" - }, + }, "0.4.18": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" - ], + ], "released": "2017-10-18" - }, + }, "0.4.19": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" - ], + ], "released": "2017-11-30" - }, + }, "0.4.2": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", - "HighOrderByteCleanStorage", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", + "HighOrderByteCleanStorage", "OptimizerStaleKnowledgeAboutSHA3" - ], + ], "released": "2016-09-17" - }, + }, "0.4.20": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" - ], + ], "released": "2018-02-14" - }, + }, "0.4.21": { "bugs": [ + "EventStructWrongData", "NestedArrayFunctionCallDecoder" - ], + ], "released": "2018-03-07" - }, + }, "0.4.22": { "bugs": [ + "EventStructWrongData", "OneOfTwoConstructorsSkipped" - ], + ], "released": "2018-04-16" - }, + }, "0.4.23": { - "bugs": [], + "bugs": [ + "EventStructWrongData" + ], "released": "2018-04-19" - }, + }, "0.4.24": { - "bugs": [], + "bugs": [ + "EventStructWrongData" + ], "released": "2018-05-16" - }, + }, "0.4.3": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", "HighOrderByteCleanStorage" - ], + ], "released": "2016-10-25" - }, + }, "0.4.4": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", "IdentityPrecompileReturnIgnored" - ], + ], "released": "2016-10-31" - }, + }, "0.4.5": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", - "IdentityPrecompileReturnIgnored", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", + "IdentityPrecompileReturnIgnored", "OptimizerStateKnowledgeNotResetForJumpdest" - ], + ], "released": "2016-11-21" - }, + }, "0.4.6": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", - "ConstantOptimizerSubtraction", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", + "ConstantOptimizerSubtraction", "IdentityPrecompileReturnIgnored" - ], + ], "released": "2016-11-22" - }, + }, "0.4.7": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", "ConstantOptimizerSubtraction" - ], + ], "released": "2016-12-15" - }, + }, "0.4.8": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", "ConstantOptimizerSubtraction" - ], + ], "released": "2017-01-13" - }, + }, "0.4.9": { "bugs": [ - "NestedArrayFunctionCallDecoder", - "ZeroFunctionSelector", - "DelegateCallReturnValue", - "ECRecoverMalformedInput", - "SkipEmptyStringLiteral", + "NestedArrayFunctionCallDecoder", + "ZeroFunctionSelector", + "DelegateCallReturnValue", + "ECRecoverMalformedInput", + "SkipEmptyStringLiteral", "ConstantOptimizerSubtraction" - ], + ], "released": "2017-01-31" } }
\ No newline at end of file diff --git a/docs/contracts.rst b/docs/contracts.rst index 4139190d..669a374f 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -26,8 +26,8 @@ Creating contracts programmatically on Ethereum is best done via using the JavaS As of today it has a method called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_ to facilitate contract creation. -When a contract is created, its constructor (a function declared with the -``constructor`` keyword) is executed once. +When a contract is created, its constructor_ (a function declared with the ``constructor`` keyword) is executed once. + A constructor is optional. Only one constructor is allowed, and this means overloading is not supported. @@ -261,7 +261,37 @@ it is evaluated as a state variable. If it is accessed externally } } -The next example is a bit more complex: +If you have a `public` state variable of array type, then you can only retrieve +single elements of the array via the generated getter function. This mechanism +exists to avoid high gas costs when returning an entire array. You can use +arguments to specify which individual element to return, for example +``data(0)``. If you want to return an entire array in one call, then you need +to write a function, for example: + +:: + + pragma solidity ^0.4.0; + contract arrayExample { + // public state variable + uint[] public myArray; + + // Getter function generated by the compiler + /* + function myArray(uint i) returns (uint) { + return myArray[i]; + } + */ + + // function that returns entire array + function getArray() returns (uint[] memory) { + return myArray; + } + } + +Now you can use ``getArray()`` to retrieve the entire array, instead of +``myArray(i)``, which returns a single element per call. + +The next example is more complex: :: @@ -276,16 +306,16 @@ The next example is a bit more complex: mapping (uint => mapping(bool => Data[])) public data; } -It will generate a function of the following form:: +It generates a function of the following form. The mapping in the struct is omitted +because there is no good way to provide the key for the mapping: + +:: function data(uint arg1, bool arg2, uint arg3) public returns (uint a, bytes3 b) { a = data[arg1][arg2][arg3].a; b = data[arg1][arg2][arg3].b; } -Note that the mapping in the struct is omitted because there -is no good way to provide the key for the mapping. - .. index:: ! function;modifier .. _modifiers: @@ -994,12 +1024,26 @@ virtual method lookup. .. index:: ! constructor +.. _constructor: + Constructors ============ -A constructor is an optional function declared with the ``constructor`` keyword which is executed upon contract creation. -Constructor functions can be either ``public`` or ``internal``. If there is no constructor, the contract will assume the -default constructor: ``contructor() public {}``. +A constructor is an optional function declared with the ``constructor`` keyword +which is executed upon contract creation, and where you can run contract +initialisation code. + +Before the constructor code is executed, state variables are initialised to +their specified value if you initialise them inline, or zero if you do not. + +After the final code of the contract is returned. The final deployment of +the code costs additional gas linear to the length of the code. If you did not +supply enough gas to initiate the state variables declared in the constructor, +then an "out of gas" exception is generated. + +Constructor functions can be either ``public`` or ``internal``. If there is no +constructor, the contract will assume the default constructor, which is +equivalent to ``constructor() public {}``. For example: :: diff --git a/docs/contributing.rst b/docs/contributing.rst index 160e73b3..8a83ca55 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -207,13 +207,13 @@ Next, build Solidity (or just the ``solfuzzer`` binary) with AFL as your compile 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> + + 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 + [100%] Linking CXX executable solfuzzer If the instrumentation messages did not appear, try switching the cmake flags pointing to AFL's clang binaries: @@ -228,7 +228,7 @@ Othwerise, upon execution the fuzzer will halt with an error saying binary is no :: - afl-fuzz 2.52b by <lcamtuf@google.com> + afl-fuzz 2.52b by <lcamtuf@google.com> ... (truncated messages) [*] Validating target binary... diff --git a/docs/control-structures.rst b/docs/control-structures.rst index def75132..d0e58908 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -412,11 +412,11 @@ The deprecated keyword ``throw`` can also be used as an alternative to ``revert( From version 0.4.13 the ``throw`` keyword is deprecated and will be phased out in the future. When exceptions happen in a sub-call, they "bubble up" (i.e. exceptions are rethrown) automatically. Exceptions to this rule are ``send`` -and the low-level functions ``call``, ``delegatecall`` and ``callcode`` -- those return ``false`` in case +and the low-level functions ``call``, ``delegatecall``, ``callcode`` and ``staticcall`` -- those return ``false`` in case of an exception instead of "bubbling up". .. warning:: - The low-level ``call``, ``delegatecall`` and ``callcode`` will return success if the called account is non-existent, as part of the design of EVM. Existence must be checked prior to calling if desired. + The low-level ``call``, ``delegatecall``, ``callcode`` and ``staticcall`` will return success if the called account is non-existent, as part of the design of EVM. Existence must be checked prior to calling if desired. Catching exceptions is not yet possible. @@ -455,7 +455,7 @@ A ``require``-style exception is generated in the following situations: #. Calling ``throw``. #. Calling ``require`` with an argument that evaluates to ``false``. -#. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall`` or ``callcode`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``. +#. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall``, ``callcode`` or ``staticcall`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``. #. If you create a contract using the ``new`` keyword but the contract creation does not finish properly (see above for the definition of "not finish properly"). #. If you perform an external function call targeting a contract that contains no code. #. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function). diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 2c5f8661..d2b7de9c 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -238,13 +238,6 @@ The key point is that the calling contract needs to know about the function it i See `ping.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/45_ping.sol>`_ and `pong.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/45_pong.sol>`_. -Get contract to do something when it is first mined -=================================================== - -Use the constructor. Anything inside it will be executed when the contract is first mined. - -See `replicator.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/50_replicator.sol>`_. - How do you create 2-dimensional arrays? ======================================= @@ -410,28 +403,6 @@ Is it possible to return an array of strings (``string[]``) from a Solidity func Not yet, as this requires two levels of dynamic arrays (``string`` is a dynamic array itself). -If you issue a call for an array, it is possible to retrieve the whole array? Or must you write a helper function for that? -=========================================================================================================================== - -The automatic :ref:`getter function<getter-functions>` for a public state variable of array type only returns -individual elements. If you want to return the complete array, you have to -manually write a function to do that. - - -What could have happened if an account has storage value(s) but no code? Example: http://test.ether.camp/account/5f740b3a43fbb99724ce93a879805f4dc89178b5 -========================================================================================================================================================== - -The last thing a constructor does is returning the code of the contract. -The gas costs for this depend on the length of the code and it might be -that the supplied gas is not enough. This situation is the only one -where an "out of gas" exception does not revert changes to the state, -i.e. in this case the initialisation of the state variables. - -https://github.com/ethereum/wiki/wiki/Subtleties - -After a successful CREATE operation's sub-execution, if the operation returns x, 5 * len(x) gas is subtracted from the remaining gas before the contract is created. If the remaining gas is less than 5 * len(x), then no gas is subtracted, the code of the created contract becomes the empty string, but this is not treated as an exceptional condition - no reverts happen. - - What does the following strange check do in the Custom Token contract? ====================================================================== diff --git a/docs/index.rst b/docs/index.rst index d59d476e..9f2844c7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -141,14 +141,14 @@ Solidity Tools * `ABI to solidity interface converter <https://gist.github.com/chriseth/8f533d133fa0c15b0d6eaf3ec502c82b>`_ A script for generating contract interfaces from the ABI of a smart contract. - -* `Securify <https://securify.ch/>`_ + +* `Securify <https://securify.ch/>`_ Fully automated online static analyzer for smart contracts, providing a security report based on vulnerability patterns. - + * `Sūrya <https://github.com/ConsenSys/surya/>`_ Utility tool for smart contract systems, offering a number of visual outputs and information about the contracts' structure. Also supports querying the function call graph. - -* `EVM Lab <https://github.com/ethereum/evmlab/>`_ + +* `EVM Lab <https://github.com/ethereum/evmlab/>`_ Rich tool package to interact with the EVM. Includes a VM, Etherchain API, and a trace-viewer with gas cost display. .. note:: diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 910f80cf..a1372f4c 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -35,7 +35,7 @@ npm / Node.js ============= Use `npm` for a convenient and portable way to install `solcjs`, a Solidity compiler. The -`solcjs` program has fewer features than all options further down this page. Our +`solcjs` program has fewer features than all options further down this page. Our :ref:`commandline-compiler` documentation assumes you are using the full-featured compiler, `solc`. So if you install `solcjs` from `npm` then you will stop reading the documentation here and then continue to `solc-js <https://github.com/ethereum/solc-js>`_. @@ -92,7 +92,7 @@ If you want to use the cutting edge developer version: sudo add-apt-repository ppa:ethereum/ethereum-dev sudo apt-get update sudo apt-get install solc - + We are also releasing a `snap package <https://snapcraft.io/>`_, which is installable in all the `supported Linux distros <https://snapcraft.io/docs/core/install>`_. To install the latest stable version of solc: .. code-block:: bash @@ -123,13 +123,13 @@ We will re-add the pre-built bottles soon. brew tap ethereum/ethereum brew install solidity -If you need a specific version of Solidity you can install a +If you need a specific version of Solidity you can install a Homebrew formula directly from Github. -View +View `solidity.rb commits on Github <https://github.com/ethereum/homebrew-ethereum/commits/master/solidity.rb>`_. -Follow the history links until you have a raw file link of a +Follow the history links until you have a raw file link of a specific commit of ``solidity.rb``. Install it using ``brew``: @@ -272,7 +272,7 @@ Building Solidity is quite similar on Linux, macOS and other Unices: or even easier: .. code-block:: bash - + #note: this will install binaries solc and soltest at usr/local/bin ./scripts/build.sh @@ -302,7 +302,7 @@ If you are interested what CMake options are available run ``cmake .. -LH``. SMT Solvers ----------- -Solidity can be built against SMT solvers and will do so by default if +Solidity can be built against SMT solvers and will do so by default if they are found in the system. Each solver can be disabled by a `cmake` option. *Note: In some cases, this can also be a potential workaround for build failures.* @@ -313,7 +313,7 @@ Inside the build folder you can disable them, since they are enabled by default: .. code-block:: bash # disables only Z3 SMT Solver. - cmake .. -DUSE_Z3=OFF + cmake .. -DUSE_Z3=OFF # disables only CVC4 SMT Solver. cmake .. -DUSE_CVC4=OFF diff --git a/docs/make.bat b/docs/make.bat index de2bccf7..bc06e706 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,242 +1,242 @@ -@ECHO OFF
-
-REM Command file for Sphinx documentation
-
-if "%SPHINXBUILD%" == "" (
- set SPHINXBUILD=sphinx-build
-)
-set BUILDDIR=_build
-set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
-set I18NSPHINXOPTS=%SPHINXOPTS% .
-if NOT "%PAPER%" == "" (
- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
- set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
-)
-
-if "%1" == "" goto help
-
-if "%1" == "help" (
- :help
- echo.Please use `make ^<target^>` where ^<target^> is one of
- echo. html to make standalone HTML files
- echo. dirhtml to make HTML files named index.html in directories
- echo. singlehtml to make a single large HTML file
- echo. pickle to make pickle files
- echo. json to make JSON files
- echo. htmlhelp to make HTML files and a HTML help project
- echo. qthelp to make HTML files and a qthelp project
- echo. devhelp to make HTML files and a Devhelp project
- echo. epub to make an epub
- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
- echo. text to make text files
- echo. man to make manual pages
- echo. texinfo to make Texinfo files
- echo. gettext to make PO message catalogs
- echo. changes to make an overview over all changed/added/deprecated items
- echo. xml to make Docutils-native XML files
- echo. pseudoxml to make pseudoxml-XML files for display purposes
- echo. linkcheck to check all external links for integrity
- echo. doctest to run all doctests embedded in the documentation if enabled
- goto end
-)
-
-if "%1" == "clean" (
- for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
- del /q /s %BUILDDIR%\*
- goto end
-)
-
-
-%SPHINXBUILD% 2> nul
-if errorlevel 9009 (
- echo.
- echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
- echo.installed, then set the SPHINXBUILD environment variable to point
- echo.to the full path of the 'sphinx-build' executable. Alternatively you
- echo.may add the Sphinx directory to PATH.
- echo.
- echo.If you don't have Sphinx installed, grab it from
- echo.http://sphinx-doc.org/
- exit /b 1
-)
-
-if "%1" == "html" (
- %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/html.
- goto end
-)
-
-if "%1" == "dirhtml" (
- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
- goto end
-)
-
-if "%1" == "singlehtml" (
- %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
- goto end
-)
-
-if "%1" == "pickle" (
- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the pickle files.
- goto end
-)
-
-if "%1" == "json" (
- %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can process the JSON files.
- goto end
-)
-
-if "%1" == "htmlhelp" (
- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run HTML Help Workshop with the ^
-.hhp project file in %BUILDDIR%/htmlhelp.
- goto end
-)
-
-if "%1" == "qthelp" (
- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; now you can run "qcollectiongenerator" with the ^
-.qhcp project file in %BUILDDIR%/qthelp, like this:
- echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Solidity.qhcp
- echo.To view the help file:
- echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Solidity.ghc
- goto end
-)
-
-if "%1" == "devhelp" (
- %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished.
- goto end
-)
-
-if "%1" == "epub" (
- %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The epub file is in %BUILDDIR%/epub.
- goto end
-)
-
-if "%1" == "latex" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "latexpdf" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- cd %BUILDDIR%/latex
- make all-pdf
- cd %BUILDDIR%/..
- echo.
- echo.Build finished; the PDF files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "latexpdfja" (
- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
- cd %BUILDDIR%/latex
- make all-pdf-ja
- cd %BUILDDIR%/..
- echo.
- echo.Build finished; the PDF files are in %BUILDDIR%/latex.
- goto end
-)
-
-if "%1" == "text" (
- %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The text files are in %BUILDDIR%/text.
- goto end
-)
-
-if "%1" == "man" (
- %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The manual pages are in %BUILDDIR%/man.
- goto end
-)
-
-if "%1" == "texinfo" (
- %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
- goto end
-)
-
-if "%1" == "gettext" (
- %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
- goto end
-)
-
-if "%1" == "changes" (
- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
- if errorlevel 1 exit /b 1
- echo.
- echo.The overview file is in %BUILDDIR%/changes.
- goto end
-)
-
-if "%1" == "linkcheck" (
- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
- if errorlevel 1 exit /b 1
- echo.
- echo.Link check complete; look for any errors in the above output ^
-or in %BUILDDIR%/linkcheck/output.txt.
- goto end
-)
-
-if "%1" == "doctest" (
- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
- if errorlevel 1 exit /b 1
- echo.
- echo.Testing of doctests in the sources finished, look at the ^
-results in %BUILDDIR%/doctest/output.txt.
- goto end
-)
-
-if "%1" == "xml" (
- %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The XML files are in %BUILDDIR%/xml.
- goto end
-)
-
-if "%1" == "pseudoxml" (
- %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
- if errorlevel 1 exit /b 1
- echo.
- echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
- goto end
-)
-
-:end
+@ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^<target^>` where ^<target^> is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Solidity.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Solidity.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %BUILDDIR%/.. + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end diff --git a/docs/metadata.rst b/docs/metadata.rst index 5e37219e..059faad2 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -131,7 +131,7 @@ user interface for the contract. Furthermore, Mist can use the userdoc to display a confirmation message to the user whenever they interact with the contract. -Additional information about Ethereum Natural Specification (NatSpec) can be found `here <https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format>`_. +Additional information about Ethereum Natural Specification (NatSpec) can be found `here <https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format>`_. Usage for Source Code Verification ================================== diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index e8631224..87041be6 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -87,10 +87,14 @@ Solidity always places new objects at the free memory pointer and memory is neve Layout of Call Data ******************* -When a Solidity contract is deployed and when it is called from an -account, the input data is assumed to be in the format in :ref:`the ABI -specification <ABI>`. The ABI specification requires arguments to be padded to multiples of 32 -bytes. The internal function calls use a different convention. +The input data for a function call is assumed to be in the format defined by the :ref:`ABI +specification <ABI>`. Among others, the ABI specification requires arguments to be padded to multiples of 32 +bytes. The internal function calls use a different convention. + +Arguments for the constructor of a contract are directly appended at the end of the +contract's code, also in ABI encoding. The constructor will access them through a hard-coded offset, and +not by using the ``codesize`` opcode, since this of course changes when appending +data to the code. .. index: variable cleanup diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 5bb3d81d..066a31ea 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -171,7 +171,8 @@ before they interact with your contract. Note that ``.send()`` does **not** throw an exception if the call stack is depleted but rather returns ``false`` in that case. The low-level functions -``.call()``, ``.callcode()`` and ``.delegatecall()`` behave in the same way. +``.call()``, ``.callcode()``, ``.delegatecall()`` and ``.staticcall()`` behave +in the same way. tx.origin ========= diff --git a/docs/types.rst b/docs/types.rst index 6024cbb7..03fd36d9 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -91,7 +91,7 @@ Operators: defined in the latter. Generally, in floating point almost the entire space is used to represent the number, while only a small number of bits define where the decimal point is. -.. index:: address, balance, send, call, callcode, delegatecall, transfer +.. index:: address, balance, send, call, callcode, delegatecall, staticcall, transfer .. _address: @@ -146,7 +146,7 @@ Send is the low-level counterpart of ``transfer``. If the execution fails, the c to make safe Ether transfers, always check the return value of ``send``, use ``transfer`` or even better: use a pattern where the recipient withdraws the money. -* ``call``, ``callcode`` and ``delegatecall`` +* ``call``, ``callcode``, ``delegatecall`` and ``staticcall`` Furthermore, to interface with contracts that do not adhere to the ABI, or to get more direct control over the encoding, @@ -189,7 +189,9 @@ Lastly, these modifiers can be combined. Their order does not matter:: In a similar way, the function ``delegatecall`` can be used: the difference is that only the code of the given address is used, all other aspects (storage, balance, ...) are taken from the current contract. The purpose of ``delegatecall`` is to use library code which is stored in another contract. The user has to ensure that the layout of storage in both contracts is suitable for delegatecall to be used. Prior to homestead, only a limited variant called ``callcode`` was available that did not provide access to the original ``msg.sender`` and ``msg.value`` values. -All three functions ``call``, ``delegatecall`` and ``callcode`` are very low-level functions and should only be used as a *last resort* as they break the type-safety of Solidity. +Since byzantium ``staticcall`` can be used as well. This is basically the same as ``call``, but will revert, if the called function modifies the state in any way. + +All four functions ``call``, ``delegatecall``, ``callcode`` and ``staticcall`` are very low-level functions and should only be used as a *last resort* as they break the type-safety of Solidity. The ``.gas()`` option is available on all three methods, while the ``.value()`` option is not supported for ``delegatecall``. diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index ceabee4e..55911dc6 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -103,7 +103,7 @@ ABI Encoding and Decoding Functions - ``abi.encode(...) returns (bytes)``: ABI-encodes the given arguments - ``abi.encodePacked(...) returns (bytes)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments - ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector -- ``abi.encodeWithSignature(string signature, ...) returns (bytes)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)``` +- ``abi.encodeWithSignature(string signature, ...) returns (bytes)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)``` .. note:: These encoding functions can be used to craft data for function calls without actually @@ -153,7 +153,7 @@ Mathematical and Cryptographic Functions It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net. -.. index:: balance, send, transfer, call, callcode, delegatecall +.. index:: balance, send, transfer, call, callcode, delegatecall, staticcall .. _address_related: Address Related @@ -171,6 +171,8 @@ Address Related issue low-level ``CALLCODE`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable ``<address>.delegatecall(bytes memory) returns (bool)``: issue low-level ``DELEGATECALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable +``<address>.staticcall(bytes memory) returns (bool)``: + issue low-level ``STATICCALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable For more information, see the section on :ref:`address`. @@ -189,8 +191,8 @@ For more information, see the section on :ref:`address`. must align in order for the called contract to correctly access the storage variables of the calling contract by name. This is of course not the case if storage pointers are passed as function arguments as in the case for the high-level libraries. - - + + .. note:: The use of ``callcode`` is discouraged and will be removed in the future. diff --git a/libdevcore/Exceptions.cpp b/libdevcore/Exceptions.cpp index 97f03f6e..cff5abf4 100644 --- a/libdevcore/Exceptions.cpp +++ b/libdevcore/Exceptions.cpp @@ -25,7 +25,7 @@ char const* Exception::what() const noexcept // Return the comment if available. if (string const* cmt = comment()) return cmt->data(); - + // Fallback to base what(). // Boost accepts nullptr, but the C++ standard doesn't // and crashes on some platforms. diff --git a/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp index dae591df..2568e17d 100644 --- a/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp +++ b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp @@ -1,8 +1,8 @@ -// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58. +// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58. #ifdef BOOST_MP_COMPARE_HPP -#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp +#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp #endif /////////////////////////////////////////////////////////////////////////////// @@ -150,11 +150,11 @@ template <class B, expression_template_option ET> struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {}; template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4> -struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> > +struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> > : public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {}; template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET> -struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> > +struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> > : public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {}; template <class Backend, expression_template_option ExpressionTemplates> @@ -196,7 +196,7 @@ inline bool operator == (const number<Backend, ExpressionTemplates>& a, const nu return eval_eq(a.backend(), b.backend()); } template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { using default_ops::eval_eq; @@ -204,7 +204,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); } template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { using default_ops::eval_eq; @@ -212,7 +212,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); } template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -222,7 +222,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return eval_eq(t.backend(), result_type::canonical_value(a)); } template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -232,7 +232,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return eval_eq(t.backend(), result_type::canonical_value(b)); } template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> -inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { using default_ops::eval_eq; @@ -250,7 +250,7 @@ inline bool operator != (const number<Backend, ExpressionTemplates>& a, const nu return !eval_eq(a.backend(), b.backend()); } template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { using default_ops::eval_eq; @@ -258,7 +258,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b)); } template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { using default_ops::eval_eq; @@ -266,7 +266,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a)); } template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -276,7 +276,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return !eval_eq(t.backend(), result_type::canonical_value(a)); } template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -286,7 +286,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return !eval_eq(t.backend(), result_type::canonical_value(b)); } template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> -inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { using default_ops::eval_eq; @@ -304,7 +304,7 @@ inline bool operator < (const number<Backend, ExpressionTemplates>& a, const num return eval_lt(a.backend(), b.backend()); } template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { using default_ops::eval_lt; @@ -312,7 +312,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); } template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { using default_ops::eval_gt; @@ -320,7 +320,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); } template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -330,7 +330,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return eval_gt(t.backend(), result_type::canonical_value(a)); } template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -340,7 +340,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return eval_lt(t.backend(), result_type::canonical_value(b)); } template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> -inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { using default_ops::eval_lt; @@ -358,7 +358,7 @@ inline bool operator > (const number<Backend, ExpressionTemplates>& a, const num return eval_gt(a.backend(), b.backend()); } template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { using default_ops::eval_gt; @@ -366,7 +366,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); } template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { using default_ops::eval_lt; @@ -374,7 +374,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); } template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -384,7 +384,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return a > t; } template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -394,7 +394,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return t > b; } template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> -inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { using default_ops::eval_gt; @@ -412,7 +412,7 @@ inline bool operator <= (const number<Backend, ExpressionTemplates>& a, const nu return !eval_gt(a.backend(), b.backend()); } template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { using default_ops::eval_gt; @@ -420,7 +420,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); } template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { using default_ops::eval_lt; @@ -428,7 +428,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); } template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -440,7 +440,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return !eval_lt(t.backend(), result_type::canonical_value(a)); } template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -450,7 +450,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return !eval_gt(t.backend(), result_type::canonical_value(b)); } template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> -inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { using default_ops::eval_gt; @@ -468,7 +468,7 @@ inline bool operator >= (const number<Backend, ExpressionTemplates>& a, const nu return !eval_lt(a.backend(), b.backend()); } template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) { using default_ops::eval_lt; @@ -476,7 +476,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); } template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> -inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) { using default_ops::eval_gt; @@ -484,7 +484,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, Expre return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); } template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -494,7 +494,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return !eval_gt(t.backend(), result_type::canonical_value(a)); } template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> -inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type +inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) { typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; @@ -504,7 +504,7 @@ inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expr return !eval_lt(t.backend(), result_type::canonical_value(b)); } template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> -inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type +inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) { using default_ops::eval_lt; diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index f33de7b7..8750b47b 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -332,7 +332,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) case Location::Memory: return "\"memory\""; case Location::Storage: return "\"storage\""; case Location::CallData: return "\"calldata\""; - case Location::Default: return "none"; + case Location::Unspecified: return "none"; } return {}; }; @@ -368,12 +368,12 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) // Find correct data location. if (_variable.isEventParameter()) { - solAssert(varLoc == Location::Default, ""); + solAssert(varLoc == Location::Unspecified, ""); typeLoc = DataLocation::Memory; } else if (_variable.isStateVariable()) { - solAssert(varLoc == Location::Default, ""); + solAssert(varLoc == Location::Unspecified, ""); typeLoc = _variable.isConstant() ? DataLocation::Memory : DataLocation::Storage; } else if ( @@ -394,7 +394,7 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) case Location::CallData: typeLoc = DataLocation::CallData; break; - case Location::Default: + case Location::Unspecified: solAssert(!_variable.hasReferenceOrMappingType(), "Data location not properly set."); } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 43e894e5..ae733cff 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -819,7 +819,9 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) ) m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables."); - if (varType->category() == Type::Category::Array) + switch (varType->category()) + { + case Type::Category::Array: if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get())) if ( ((arrayType->location() == DataLocation::Memory) || @@ -827,6 +829,18 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) !arrayType->validForCalldata() ) m_errorReporter.typeError(_variable.location(), "Array is too large to be encoded."); + break; + case Type::Category::Mapping: + if (auto mappingType = dynamic_cast<MappingType const*>(varType.get())) + if ( + mappingType->keyType()->isDynamicallySized() && + _variable.visibility() == Declaration::Visibility::Public + ) + m_errorReporter.typeError(_variable.location(), "Dynamically-sized keys for public mappings are not supported."); + break; + default: + break; + } return false; } @@ -895,7 +909,17 @@ bool TypeChecker::visit(EventDefinition const& _eventDef) for (ASTPointer<VariableDeclaration> const& var: _eventDef.parameters()) { if (var->isIndexed()) + { numIndexed++; + if ( + _eventDef.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) && + dynamic_cast<ReferenceType const*>(type(*var).get()) + ) + m_errorReporter.typeError( + var->location(), + "Indexed reference types cannot yet be used with ABIEncoderV2." + ); + } if (!type(*var)->canLiveOutsideStorage()) m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); if (!type(*var)->interfaceType(false)) @@ -1193,7 +1217,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) if (ref->dataStoredIn(DataLocation::Storage)) { string errorText{"Uninitialized storage pointer."}; - if (varDecl.referenceLocation() == VariableDeclaration::Location::Default) + if (varDecl.referenceLocation() == VariableDeclaration::Location::Unspecified) errorText += " Did you mean '<type> memory " + varDecl.name() + "'?"; solAssert(m_scope, ""); m_errorReporter.declarationError(varDecl.location(), errorText); @@ -1359,7 +1383,8 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement) if ( kind == FunctionType::Kind::BareCall || kind == FunctionType::Kind::BareCallCode || - kind == FunctionType::Kind::BareDelegateCall + kind == FunctionType::Kind::BareDelegateCall || + kind == FunctionType::Kind::BareStaticCall ) m_errorReporter.warning(_statement.location(), "Return value of low-level calls not used."); else if (kind == FunctionType::Kind::Send) @@ -1754,6 +1779,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) return false; } + if (functionType->kind() == FunctionType::Kind::BareStaticCall && !m_evmVersion.hasStaticCall()) + m_errorReporter.typeError(_functionCall.location(), "\"staticcall\" is not supported by the VM version."); + auto returnTypes = allowDynamicTypes ? functionType->returnParameterTypes() : @@ -1834,7 +1862,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) else if ( functionType->kind() == FunctionType::Kind::BareCall || functionType->kind() == FunctionType::Kind::BareCallCode || - functionType->kind() == FunctionType::Kind::BareDelegateCall + functionType->kind() == FunctionType::Kind::BareDelegateCall || + functionType->kind() == FunctionType::Kind::BareStaticCall ) { if (arguments.empty()) @@ -1882,7 +1911,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) if ( functionType->kind() == FunctionType::Kind::BareCall || functionType->kind() == FunctionType::Kind::BareCallCode || - functionType->kind() == FunctionType::Kind::BareDelegateCall + functionType->kind() == FunctionType::Kind::BareDelegateCall || + functionType->kind() == FunctionType::Kind::BareStaticCall ) msg += " This function requires a single bytes argument. If all your arguments are value types, you can use abi.encode(...) to properly generate it."; else if ( diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index a376e55d..8e7a81a6 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -397,7 +397,7 @@ SourceUnit const& Scopable::sourceUnit() const { ASTNode const* s = scope(); solAssert(s, ""); - // will not always be a declaratoion + // will not always be a declaration while (dynamic_cast<Scopable const*>(s) && dynamic_cast<Scopable const*>(s)->scope()) s = dynamic_cast<Scopable const*>(s)->scope(); return dynamic_cast<SourceUnit const&>(*s); @@ -517,7 +517,7 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c using Location = VariableDeclaration::Location; if (!hasReferenceOrMappingType() || isStateVariable() || isEventParameter()) - return set<Location>{ Location::Default }; + return set<Location>{ Location::Unspecified }; else if (isStateVariable() && isConstant()) return set<Location>{ Location::Memory }; else if (isExternalCallableParameter()) @@ -546,7 +546,7 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c } else // Struct members etc. - return set<Location>{ Location::Default }; + return set<Location>{ Location::Unspecified }; } TypePointer VariableDeclaration::type() const diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index b953211d..a5cd277d 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -655,7 +655,7 @@ private: class VariableDeclaration: public Declaration { public: - enum Location { Default, Storage, Memory, CallData }; + enum Location { Unspecified, Storage, Memory, CallData }; VariableDeclaration( SourceLocation const& _sourceLocation, @@ -666,7 +666,7 @@ public: bool _isStateVar = false, bool _isIndexed = false, bool _isConstant = false, - Location _referenceLocation = Location::Default + Location _referenceLocation = Location::Unspecified ): Declaration(_sourceLocation, _name, _visibility), m_typeName(_type), diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 72b20b3b..beab356c 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -739,7 +739,7 @@ string ASTJsonConverter::location(VariableDeclaration::Location _location) { switch (_location) { - case VariableDeclaration::Location::Default: + case VariableDeclaration::Location::Unspecified: return "default"; case VariableDeclaration::Location::Storage: return "storage"; diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index c9dca126..e1e8403c 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -621,6 +621,7 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons {"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)}, {"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareDelegateCall, false)}, {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}, + {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)}, {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)} }; else @@ -1500,8 +1501,6 @@ TypePointer ReferenceType::unaryOperatorResult(Token::Value _operator) const return make_shared<TupleType>(); case DataLocation::Storage: return m_isPointer ? TypePointer() : make_shared<TupleType>(); - default: - solAssert(false, ""); } return TypePointer(); } @@ -1547,8 +1546,6 @@ string ReferenceType::identifierLocationSuffix() const case DataLocation::CallData: id += "_calldata"; break; - default: - solAssert(false, "Unknown location returned by location()"); } if (isPointer()) id += "_ptr"; @@ -2495,7 +2492,7 @@ TypePointers FunctionType::returnParameterTypesWithoutDynamicTypes() const { TypePointers returnParameterTypes = m_returnParameterTypes; - if (m_kind == Kind::External || m_kind == Kind::CallCode || m_kind == Kind::DelegateCall) + if (m_kind == Kind::External || m_kind == Kind::DelegateCall) for (auto& param: returnParameterTypes) if (param->isDynamicallySized() && !param->dataStoredIn(DataLocation::Storage)) param = make_shared<InaccessibleDynamicType>(); @@ -2517,11 +2514,11 @@ string FunctionType::richIdentifier() const { case Kind::Internal: id += "internal"; break; case Kind::External: id += "external"; break; - case Kind::CallCode: id += "callcode"; break; case Kind::DelegateCall: id += "delegatecall"; break; case Kind::BareCall: id += "barecall"; break; case Kind::BareCallCode: id += "barecallcode"; break; case Kind::BareDelegateCall: id += "baredelegatecall"; break; + case Kind::BareStaticCall: id += "barestaticcall"; break; case Kind::Creation: id += "creation"; break; case Kind::Send: id += "send"; break; case Kind::Transfer: id += "transfer"; break; @@ -2554,7 +2551,6 @@ string FunctionType::richIdentifier() const case Kind::ABIEncodeWithSelector: id += "abiencodewithselector"; break; case Kind::ABIEncodeWithSignature: id += "abiencodewithsignature"; break; case Kind::ABIDecode: id += "abidecode"; break; - default: solAssert(false, "Unknown function location."); break; } id += "_" + stateMutabilityToString(m_stateMutability); id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes); @@ -2698,13 +2694,13 @@ unsigned FunctionType::sizeOnStack() const switch(kind) { case Kind::External: - case Kind::CallCode: case Kind::DelegateCall: size = 2; break; case Kind::BareCall: case Kind::BareCallCode: case Kind::BareDelegateCall: + case Kind::BareStaticCall: case Kind::Internal: case Kind::ArrayPush: case Kind::ArrayPop: @@ -2772,6 +2768,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con case Kind::BareCall: case Kind::BareCallCode: case Kind::BareDelegateCall: + case Kind::BareStaticCall: { MemberList::MemberMap members; if (m_kind == Kind::External) @@ -2911,6 +2908,7 @@ bool FunctionType::isBareCall() const case Kind::BareCall: case Kind::BareCallCode: case Kind::BareDelegateCall: + case Kind::BareStaticCall: case Kind::ECRecover: case Kind::SHA256: case Kind::RIPEMD160: @@ -2924,6 +2922,16 @@ string FunctionType::externalSignature() const { solAssert(m_declaration != nullptr, "External signature of function needs declaration"); solAssert(!m_declaration->name().empty(), "Fallback function has no signature."); + switch (kind()) + { + case Kind::Internal: + case Kind::External: + case Kind::DelegateCall: + case Kind::Event: + break; + default: + solAssert(false, "Invalid function type for requesting external signature."); + } bool const inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary(); FunctionTypePointer external = interfaceFunctionType(); @@ -3054,6 +3062,7 @@ bool FunctionType::padArguments() const case Kind::BareCall: case Kind::BareCallCode: case Kind::BareDelegateCall: + case Kind::BareStaticCall: case Kind::SHA256: case Kind::RIPEMD160: case Kind::KECCAK256: @@ -3240,8 +3249,6 @@ string MagicType::richIdentifier() const return "t_magic_transaction"; case Kind::ABI: return "t_magic_abi"; - default: - solAssert(false, "Unknown kind of magic"); } return ""; } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index d8e73ab9..b860bf6a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -899,11 +899,11 @@ public: { Internal, ///< stack-call using plain JUMP External, ///< external call using CALL - CallCode, ///< external call using CALLCODE, i.e. not exchanging the storage DelegateCall, ///< external call using DELEGATECALL, i.e. not exchanging the storage BareCall, ///< CALL without function hash BareCallCode, ///< CALLCODE without function hash BareDelegateCall, ///< DELEGATECALL without function hash + BareStaticCall, ///< STATICCALL without function hash Creation, ///< external call using CREATE Send, ///< CALL, but without data and gas Transfer, ///< CALL, but without data and throws on error @@ -935,7 +935,7 @@ public: ABIEncodeWithSelector, ABIEncodeWithSignature, ABIDecode, - GasLeft ///< gasleft() + GasLeft, ///< gasleft() }; virtual Category category() const override { return Category::Function; } @@ -1051,7 +1051,7 @@ public: /// @returns true iff the function type is equal to the given type, ignoring state mutability differences. bool equalExcludingStateMutability(FunctionType const& _other) const; - /// @returns true if the ABI is used for this call (only meaningful for external calls) + /// @returns true if the ABI is NOT used for this call (only meaningful for external calls) bool isBareCall() const; Kind const& kind() const { return m_kind; } StateMutability stateMutability() const { return m_stateMutability; } @@ -1090,6 +1090,7 @@ public: case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: return true; default: return false; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7a4548f5..a844aeb8 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -281,19 +281,19 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) { ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type); - + solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array."); m_context << max(u256(32u), arrayType.memorySize()); utils().allocateMemory(); m_context << Instruction::DUP1; - + for (auto const& component: _tuple.components()) { component->accept(*this); utils().convertType(*component->annotation().type, *arrayType.baseType(), true); - utils().storeInMemoryDynamic(*arrayType.baseType(), true); + utils().storeInMemoryDynamic(*arrayType.baseType(), true); } - + m_context << Instruction::POP; } else @@ -566,11 +566,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; } case FunctionType::Kind::External: - case FunctionType::Kind::CallCode: case FunctionType::Kind::DelegateCall: case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: _functionCall.expression().accept(*this); appendExternalFunctionCall(function, arguments); break; @@ -1164,18 +1164,18 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) solAssert(false, "event not found"); // no-op, because the parent node will do the job break; + case FunctionType::Kind::DelegateCall: + _memberAccess.expression().accept(*this); + m_context << funType->externalIdentifier(); + break; case FunctionType::Kind::External: case FunctionType::Kind::Creation: - case FunctionType::Kind::DelegateCall: - case FunctionType::Kind::CallCode: case FunctionType::Kind::Send: case FunctionType::Kind::BareCall: case FunctionType::Kind::BareCallCode: case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: case FunctionType::Kind::Transfer: - _memberAccess.expression().accept(*this); - m_context << funType->externalIdentifier(); - break; case FunctionType::Kind::Log0: case FunctionType::Kind::Log1: case FunctionType::Kind::Log2: @@ -1273,7 +1273,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) ); m_context << Instruction::BALANCE; } - else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall"}).count(member)) + else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member)) utils().convertType( *_memberAccess.expression().annotation().type, IntegerType(160, IntegerType::Modifier::Address), @@ -1569,7 +1569,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) { CompilerContext::LocationSetter locationSetter(m_context, _literal); TypePointer type = _literal.annotation().type; - + switch (type->category()) { case Type::Category::RationalNumber: @@ -1825,10 +1825,13 @@ void ExpressionCompiler::appendExternalFunctionCall( utils().moveToStackTop(gasValueSize, _functionType.selfType()->sizeOnStack()); auto funKind = _functionType.kind(); - bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall; - bool isCallCode = funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::CallCode; + + solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); + + bool returnSuccessCondition = funKind == FunctionType::Kind::BareCall || funKind == FunctionType::Kind::BareCallCode || funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::BareStaticCall; + bool isCallCode = funKind == FunctionType::Kind::BareCallCode; bool isDelegateCall = funKind == FunctionType::Kind::BareDelegateCall || funKind == FunctionType::Kind::DelegateCall; - bool useStaticCall = _functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall(); + bool useStaticCall = funKind == FunctionType::Kind::BareStaticCall || (_functionType.stateMutability() <= StateMutability::View && m_context.evmVersion().hasStaticCall()); bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); unsigned retSize = 0; @@ -1954,7 +1957,7 @@ void ExpressionCompiler::appendExternalFunctionCall( bool existenceChecked = false; // Check the the target contract exists (has code) for non-low-level calls. - if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::CallCode || funKind == FunctionType::Kind::DelegateCall) + if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall) { m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO; // TODO: error message? diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 0bee2a91..bfa0ad24 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -564,7 +564,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( bool isIndexed = false; bool isDeclaredConst = false; Declaration::Visibility visibility(Declaration::Visibility::Default); - VariableDeclaration::Location location = VariableDeclaration::Location::Default; + VariableDeclaration::Location location = VariableDeclaration::Location::Unspecified; ASTPointer<ASTString> identifier; while (true) @@ -592,7 +592,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration( isDeclaredConst = true; else if (_options.allowLocationSpecifier && Token::isLocationSpecifier(token)) { - if (location != VariableDeclaration::Location::Default) + if (location != VariableDeclaration::Location::Unspecified) parserError(string("Location already specified.")); else if (!type) parserError(string("Location specifier needs explicit type name.")); diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index 5ce74316..27acb7d4 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -63,7 +63,7 @@ void ElementaryTypeNameToken::assertDetails(Token::Value _baseType, unsigned con { solAssert(_second == 0, "There should not be a second size argument to type " + string(Token::toString(_baseType)) + "."); solAssert( - _first <= 256 && _first % 8 == 0, + _first <= 256 && _first % 8 == 0, "No elementary type " + string(Token::toString(_baseType)) + to_string(_first) + "." ); } @@ -165,7 +165,7 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s else return make_tuple(Token::FixedMxN, m, n); } - } + } } return make_tuple(Token::Identifier, 0, 0); } diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py index de2a4438..06e9f9ea 100755 --- a/scripts/isolate_tests.py +++ b/scripts/isolate_tests.py @@ -79,7 +79,7 @@ if __name__ == '__main__': if isfile(path): extract_and_write(path, path) - else: + else: for root, subdirs, files in os.walk(path): if '_build' in subdirs: subdirs.remove('_build') diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index ae565a02..1cfbf716 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -22,7 +22,7 @@ ## method = ftp ## incoming = ~ethereum/ethereum-dev ## login = anonymous -## +## ## [ethereum] ## fqdn = ppa.launchpad.net ## method = ftp diff --git a/scripts/update_bugs_by_version.py b/scripts/update_bugs_by_version.py index 68ccd72a..655ffe23 100755 --- a/scripts/update_bugs_by_version.py +++ b/scripts/update_bugs_by_version.py @@ -35,7 +35,7 @@ for v in versions: continue versions[v]['bugs'] += [bug['name']] -new_contents = json.dumps(versions, sort_keys=True, indent=4) +new_contents = json.dumps(versions, sort_keys=True, indent=4, separators=(',', ': ')) with open(path + '/../docs/bugs_by_version.json', 'r') as bugs_by_version: old_contents = bugs_by_version.read() with open(path + '/../docs/bugs_by_version.json', 'w') as bugs_by_version: diff --git a/test/libdevcore/UTF8.cpp b/test/libdevcore/UTF8.cpp index 6de4570f..daf47bb0 100644 --- a/test/libdevcore/UTF8.cpp +++ b/test/libdevcore/UTF8.cpp @@ -148,7 +148,7 @@ hélló Ḕ ḕ Ḗ ḗ Ḙ ḙ Ḛ -ἐ ἑ ἒ ἓ ἔ ἕ +ἐ ἑ ἒ ἓ ἔ ἕ ₠ ₡ ₢ ₣ ₤ ₥ @@ -164,9 +164,9 @@ hélló ␀ ␁ ␂ ␃ ␄ ␅ -⑀ ⑁ ⑂ ⑃ ⑄ +⑀ ⑁ ⑂ ⑃ ⑄ -① ② ③ ④ ⑤ +① ② ③ ④ ⑤ ╘ ╙ ╚ ╛ ╜ ╝ @@ -200,7 +200,7 @@ hélló שּׁ שּׂ אַ אָ אּ -ﮄ ﮅ ﮆ ﮇ ﮈ ﮉ +ﮄ ﮅ ﮆ ﮇ ﮈ ﮉ ﺵ ﺶ ﺷ ﺸ diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 8a334e5e..2bf20126 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3592,6 +3592,19 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws) )YY"; compileAndRun(sourceCode); ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); + + if (dev::test::Options::get().evmVersion().hasStaticCall()) + { + char const* sourceCode = R"YY( + contract A { + function f() public returns (bool) { + return address(this).staticcall(""); + } + } + )YY"; + compileAndRun(sourceCode); + ABI_CHECK(callContractFunction("f()"), encodeArgs(0)); + } } BOOST_AUTO_TEST_CASE(short_data_calls_fallback) @@ -3937,6 +3950,209 @@ BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage) BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); } +BOOST_AUTO_TEST_CASE(event_struct_memory_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + struct S { uint a; } + event E(S); + function createEvent(uint x) public { + emit E(S(x)); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(x)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint256))"))); +} + +BOOST_AUTO_TEST_CASE(event_struct_storage_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + struct S { uint a; } + event E(S); + S s; + function createEvent(uint x) public { + s.a = x; + emit E(s); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(x)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint256))"))); +} + +BOOST_AUTO_TEST_CASE(event_dynamic_array_memory) +{ + char const* sourceCode = R"( + contract C { + event E(uint[]); + function createEvent(uint x) public { + uint[] memory arr = new uint[](3); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); +} + +BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + event E(uint[]); + function createEvent(uint x) public { + uint[] memory arr = new uint[](3); + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); +} + +BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + event E(uint[][]); + function createEvent(uint x) public { + uint[][] memory arr = new uint[][](2); + arr[0] = new uint[](2); + arr[1] = new uint[](2); + arr[0][0] = x; + arr[0][1] = x + 1; + arr[1][0] = x + 2; + arr[1][1] = x + 3; + emit E(arr); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])"))); +} + +BOOST_AUTO_TEST_CASE(event_dynamic_array_storage) +{ + char const* sourceCode = R"( + contract C { + event E(uint[]); + uint[] arr; + function createEvent(uint x) public { + arr.length = 3; + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); +} + +BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + event E(uint[]); + uint[] arr; + function createEvent(uint x) public { + arr.length = 3; + arr[0] = x; + arr[1] = x + 1; + arr[2] = x + 2; + emit E(arr); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); +} + +BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2) +{ + char const* sourceCode = R"( + pragma experimental ABIEncoderV2; + contract C { + event E(uint[][]); + uint[][] arr; + function createEvent(uint x) public { + arr.length = 2; + arr[0].length = 2; + arr[1].length = 2; + arr[0][0] = x; + arr[0][1] = x + 1; + arr[1][0] = x + 2; + arr[1][1] = x + 3; + emit E(arr); + } + } + )"; + compileAndRun(sourceCode); + u256 x(42); + callContractFunction("createEvent(uint256)", x); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])"))); +} + BOOST_AUTO_TEST_CASE(event_indexed_string) { char const* sourceCode = R"( @@ -4215,6 +4431,49 @@ BOOST_AUTO_TEST_CASE(generic_delegatecall) BOOST_CHECK_EQUAL(balanceAt(c_senderAddress), 50 + 11); } +BOOST_AUTO_TEST_CASE(generic_staticcall) +{ + if (dev::test::Options::get().evmVersion().hasStaticCall()) + { + char const* sourceCode = R"**( + contract A { + uint public x; + constructor() public { x = 42; } + function pureFunction(uint256 p) public pure returns (uint256) { return p; } + function viewFunction(uint256 p) public view returns (uint256) { return p + x; } + function nonpayableFunction(uint256 p) public returns (uint256) { x = p; return x; } + function assertFunction(uint256 p) public view returns (uint256) { assert(x == p); return x; } + } + contract C { + function f(address a) public view returns (bool) + { + return a.staticcall(abi.encodeWithSignature("pureFunction(uint256)", 23)); + } + function g(address a) public view returns (bool) + { + return a.staticcall(abi.encodeWithSignature("viewFunction(uint256)", 23)); + } + function h(address a) public view returns (bool) + { + return a.staticcall(abi.encodeWithSignature("nonpayableFunction(uint256)", 23)); + } + function i(address a, uint256 v) public view returns (bool) + { + return a.staticcall(abi.encodeWithSignature("assertFunction(uint256)", v)); + } + } + )**"; + compileAndRun(sourceCode, 0, "A"); + u160 const c_addressA = m_contractAddress; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f(address)", c_addressA), encodeArgs(true)); + ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true)); + ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false)); + ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true)); + ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false)); + } +} + BOOST_AUTO_TEST_CASE(library_call_in_homestead) { char const* sourceCode = R"( @@ -12216,6 +12475,19 @@ BOOST_AUTO_TEST_CASE(bare_call_invalid_address) compileAndRun(sourceCode, 0, "C"); ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("h()"), encodeArgs(u256(1))); + + if (dev::test::Options::get().evmVersion().hasStaticCall()) + { + char const* sourceCode = R"YY( + contract C { + function f() external returns (bool) { + return address(0x4242).staticcall(""); + } + } + )YY"; + compileAndRun(sourceCode, 0, "C"); + ABI_CHECK(callContractFunction("f()"), encodeArgs(u256(1))); + } } BOOST_AUTO_TEST_CASE(delegatecall_return_value) diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 55e81867..387505a5 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -433,6 +433,37 @@ BOOST_AUTO_TEST_CASE(getter_is_memory_type) } } +BOOST_AUTO_TEST_CASE(address_staticcall) +{ + char const* sourceCode = R"( + contract C { + function f() public view returns(bool) { + return address(0x4242).staticcall(""); + } + } + )"; + + if (dev::test::Options::get().evmVersion().hasStaticCall()) + CHECK_SUCCESS_NO_WARNINGS(sourceCode); + else + CHECK_ERROR(sourceCode, TypeError, "\"staticcall\" is not supported by the VM version."); +} + +BOOST_AUTO_TEST_CASE(address_staticcall_value) +{ + if (dev::test::Options::get().evmVersion().hasStaticCall()) + { + char const* sourceCode = R"( + contract C { + function f() public view { + address(0x4242).staticcall.value; + } + } + )"; + CHECK_ERROR(sourceCode, TypeError, "Member \"value\" not found or not visible after argument-dependent lookup"); + } +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index b97df972..d77050cb 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -647,7 +647,7 @@ BOOST_AUTO_TEST_CASE(dev_documenting_no_paramname) contract test { /// @dev Multiplies a number by 7 and adds second parameter /// @param a Documentation for the first parameter - /// @param + /// @param function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; } } )"; @@ -675,7 +675,7 @@ BOOST_AUTO_TEST_CASE(dev_documenting_no_param_description) contract test { /// @dev Multiplies a number by 7 and adds second parameter /// @param a Documentation for the first parameter - /// @param second + /// @param second function mul(uint a, uint second) public returns (uint d) { return a * 7 + second; } } )"; diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp index 299cd084..d993b92e 100644 --- a/test/libsolidity/ViewPureChecker.cpp +++ b/test/libsolidity/ViewPureChecker.cpp @@ -53,8 +53,11 @@ BOOST_AUTO_TEST_CASE(environment_access) "tx.origin", "tx.gasprice", "this", - "address(1).balance" + "address(1).balance", }; + if (dev::test::Options::get().evmVersion().hasStaticCall()) + view.emplace_back("address(0x4242).staticcall(\"\")"); + // ``block.blockhash`` and ``blockhash`` are tested separately below because their usage will // produce warnings that can't be handled in a generic way. vector<string> pure{ @@ -95,6 +98,22 @@ BOOST_AUTO_TEST_CASE(environment_access) ); } +BOOST_AUTO_TEST_CASE(address_staticcall) +{ + string text = R"( + contract C { + function i() view public returns (bool) { + return address(0x4242).staticcall(""); + } + } + )"; + if (!dev::test::Options::get().evmVersion().hasStaticCall()) + CHECK_ERROR(text, TypeError, "\"staticcall\" is not supported by the VM version."); + else + CHECK_SUCCESS_NO_WARNINGS(text); +} + + BOOST_AUTO_TEST_CASE(assembly_staticcall) { string text = R"( diff --git a/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol new file mode 100644 index 00000000..aaf6028a --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_array_indexed_v2.sol @@ -0,0 +1,7 @@ +pragma experimental ABIEncoderV2; +contract c { + event E(uint[] indexed); +} +// ---- +// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError: (59-65): Indexed reference types cannot yet be used with ABIEncoderV2. diff --git a/test/libsolidity/syntaxTests/events/event_array_v2.sol b/test/libsolidity/syntaxTests/events/event_array_v2.sol new file mode 100644 index 00000000..9ccd9fc9 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_array_v2.sol @@ -0,0 +1,6 @@ +pragma experimental ABIEncoderV2; +contract c { + event E(uint[]); +} +// ---- +// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol new file mode 100644 index 00000000..ffae5b9c --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array_indexed_v2.sol @@ -0,0 +1,7 @@ +pragma experimental ABIEncoderV2; +contract c { + event E(uint[][] indexed); +} +// ---- +// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError: (59-67): Indexed reference types cannot yet be used with ABIEncoderV2. diff --git a/test/libsolidity/syntaxTests/events/event_nested_array_v2.sol b/test/libsolidity/syntaxTests/events/event_nested_array_v2.sol new file mode 100644 index 00000000..efc7439e --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_nested_array_v2.sol @@ -0,0 +1,6 @@ +pragma experimental ABIEncoderV2; +contract c { + event E(uint[][]); +} +// ---- +// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. diff --git a/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol b/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol new file mode 100644 index 00000000..a8e0837f --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_struct_indexed_v2.sol @@ -0,0 +1,8 @@ +pragma experimental ABIEncoderV2; +contract c { + struct S { uint a ; } + event E(S indexed); +} +// ---- +// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. +// TypeError: (85-86): Indexed reference types cannot yet be used with ABIEncoderV2. diff --git a/test/libsolidity/syntaxTests/events/event_struct_v2.sol b/test/libsolidity/syntaxTests/events/event_struct_v2.sol new file mode 100644 index 00000000..97ca61b6 --- /dev/null +++ b/test/libsolidity/syntaxTests/events/event_struct_v2.sol @@ -0,0 +1,7 @@ +pragma experimental ABIEncoderV2; +contract c { + struct S { uint a ; } + event E(S); +} +// ---- +// Warning: (0-33): Experimental features are turned on. Do not use experimental features on live deployments. diff --git a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_1.sol b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_1.sol new file mode 100644 index 00000000..ea2d282c --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_1.sol @@ -0,0 +1,5 @@ +contract c { + mapping(uint[] => uint) data; +} +// ---- +// ParserError: (26-27): Expected '=>' but got '[' diff --git a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol new file mode 100644 index 00000000..713cddeb --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol @@ -0,0 +1,8 @@ +contract c { + struct S { + uint x; + } + mapping(S => uint) data; +} +// ---- +// ParserError: (47-48): Expected elementary type name for mapping key type diff --git a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol new file mode 100644 index 00000000..655af9de --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol @@ -0,0 +1,8 @@ +contract c { + struct S { + string s; + } + mapping(S => uint) data; +} +// ---- +// ParserError: (49-50): Expected elementary type name for mapping key type diff --git a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_4.sol b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_4.sol new file mode 100644 index 00000000..f4dcb00a --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_4.sol @@ -0,0 +1,5 @@ +contract c { + mapping(string[] => uint) data; +} +// ---- +// ParserError: (28-29): Expected '=>' but got '[' diff --git a/test/libsolidity/syntaxTests/types/mapping/mapping_dynamic_key.sol b/test/libsolidity/syntaxTests/types/mapping/mapping_dynamic_key.sol new file mode 100644 index 00000000..825ee09a --- /dev/null +++ b/test/libsolidity/syntaxTests/types/mapping/mapping_dynamic_key.sol @@ -0,0 +1,3 @@ +contract c { + mapping(string => uint) data; +} diff --git a/test/libsolidity/syntaxTests/types/mapping/mapping_dynamic_key_public.sol b/test/libsolidity/syntaxTests/types/mapping/mapping_dynamic_key_public.sol new file mode 100644 index 00000000..9fb575af --- /dev/null +++ b/test/libsolidity/syntaxTests/types/mapping/mapping_dynamic_key_public.sol @@ -0,0 +1,5 @@ +contract c { + mapping(string => uint) public data; +} +// ---- +// TypeError: (14-49): Dynamically-sized keys for public mappings are not supported. |