aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml10
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md9
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md12
-rw-r--r--.github/ISSUE_TEMPLATE/general.md6
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md6
-rw-r--r--CMakeLists.txt2
-rw-r--r--Changelog.md34
-rw-r--r--README.md4
-rw-r--r--docs/050-breaking-changes.rst413
-rw-r--r--docs/abi-spec.rst64
-rw-r--r--docs/assembly.rst187
-rw-r--r--docs/bugs.json2
-rw-r--r--docs/bugs_by_version.json4
-rw-r--r--docs/common-patterns.rst14
-rw-r--r--docs/contracts.rst277
-rw-r--r--docs/contributing.rst84
-rw-r--r--docs/control-structures.rst102
-rw-r--r--docs/frequently-asked-questions.rst40
-rw-r--r--docs/grammar.txt3
-rw-r--r--docs/index.rst13
-rw-r--r--docs/installing-solidity.rst93
-rw-r--r--docs/introduction-to-smart-contracts.rst117
-rw-r--r--docs/layout-of-source-files.rst92
-rw-r--r--docs/metadata.rst28
-rw-r--r--docs/miscellaneous.rst56
-rw-r--r--docs/security-considerations.rst57
-rw-r--r--docs/solidity-by-example.rst37
-rw-r--r--docs/solidity-in-depth.rst3
-rw-r--r--docs/structure-of-a-contract.rst24
-rw-r--r--docs/style-guide.rst51
-rw-r--r--docs/types.rst489
-rw-r--r--docs/units-and-global-variables.rst115
-rw-r--r--docs/using-the-compiler.rst76
-rw-r--r--docs/yul.rst9
-rw-r--r--libdevcore/SHA3.cpp118
-rw-r--r--libevmasm/Assembly.cpp43
-rw-r--r--libevmasm/Assembly.h27
-rw-r--r--libevmasm/CommonSubexpressionEliminator.cpp2
-rw-r--r--libevmasm/ConstantOptimiser.cpp10
-rw-r--r--libevmasm/ExpressionClasses.cpp1
-rw-r--r--libevmasm/GasMeter.cpp24
-rw-r--r--libevmasm/GasMeter.h5
-rw-r--r--libevmasm/Instruction.cpp2
-rw-r--r--libevmasm/Instruction.h15
-rw-r--r--libevmasm/PathGasMeter.h10
-rw-r--r--libevmasm/RuleList.h47
-rw-r--r--libevmasm/SemanticInformation.cpp3
-rw-r--r--libevmasm/SimplificationRules.cpp21
-rw-r--r--libevmasm/SimplificationRules.h6
-rw-r--r--libjulia/backends/evm/AbstractAssembly.h2
-rw-r--r--libjulia/backends/evm/EVMCodeTransform.cpp8
-rw-r--r--libjulia/optimiser/FullInliner.cpp5
-rw-r--r--libjulia/optimiser/SimplificationRules.cpp7
-rw-r--r--libjulia/optimiser/SimplificationRules.h3
-rw-r--r--liblll/Compiler.cpp3
-rw-r--r--liblll/Parser.cpp3
-rw-r--r--libsolidity/analysis/GlobalContext.cpp4
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp25
-rw-r--r--libsolidity/analysis/SemVerHandler.cpp39
-rw-r--r--libsolidity/analysis/TypeChecker.cpp73
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp8
-rw-r--r--libsolidity/ast/AST.cpp17
-rw-r--r--libsolidity/ast/AST.h20
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp18
-rw-r--r--libsolidity/ast/Types.cpp91
-rw-r--r--libsolidity/ast/Types.h24
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp8
-rw-r--r--libsolidity/codegen/ArrayUtils.cpp2
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp9
-rw-r--r--libsolidity/codegen/CompilerUtils.h2
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp31
-rw-r--r--libsolidity/formal/SMTChecker.cpp2
-rw-r--r--libsolidity/formal/Z3Interface.cpp2
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp7
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h2
-rw-r--r--libsolidity/interface/CompilerStack.cpp5
-rw-r--r--libsolidity/interface/EVMVersion.h1
-rw-r--r--libsolidity/interface/Exceptions.cpp3
-rw-r--r--libsolidity/interface/GasEstimator.cpp5
-rw-r--r--libsolidity/interface/Natspec.cpp3
-rw-r--r--libsolidity/interface/SourceReferenceFormatter.cpp11
-rw-r--r--libsolidity/interface/StandardCompiler.cpp39
-rw-r--r--libsolidity/parsing/Parser.cpp30
-rw-r--r--libsolidity/parsing/Scanner.cpp6
-rw-r--r--libsolidity/parsing/Token.h7
-rwxr-xr-xscripts/check_style.sh32
-rw-r--r--scripts/codespell_whitelist.txt1
-rwxr-xr-xscripts/detect_trailing_whitespace.sh15
-rwxr-xr-xscripts/install_deps.sh5
-rwxr-xr-xscripts/isolate_tests.py7
-rwxr-xr-xscripts/tests.sh10
-rw-r--r--solc/CommandLineInterface.cpp6
-rw-r--r--test/ExecutionFramework.cpp4
-rw-r--r--test/Options.cpp23
-rw-r--r--test/cmdlineErrorReports/too_long_line.sol4
-rw-r--r--test/cmdlineErrorReports/too_long_line.sol.ref7
-rw-r--r--test/cmdlineErrorReports/too_long_line_both_sides_short.sol5
-rw-r--r--test/cmdlineErrorReports/too_long_line_both_sides_short.sol.ref7
-rw-r--r--test/cmdlineErrorReports/too_long_line_edge_in.sol4
-rw-r--r--test/cmdlineErrorReports/too_long_line_edge_in.sol.ref7
-rw-r--r--test/cmdlineErrorReports/too_long_line_edge_out.sol4
-rw-r--r--test/cmdlineErrorReports/too_long_line_edge_out.sol.ref7
-rw-r--r--test/cmdlineErrorReports/too_long_line_left_short.sol4
-rw-r--r--test/cmdlineErrorReports/too_long_line_left_short.sol.ref7
-rw-r--r--test/cmdlineErrorReports/too_long_line_right_short.sol5
-rw-r--r--test/cmdlineErrorReports/too_long_line_right_short.sol.ref7
-rwxr-xr-xtest/cmdlineTests.sh28
-rw-r--r--test/compilationTests/corion/ico.sol14
-rw-r--r--test/compilationTests/corion/module.sol22
-rw-r--r--test/compilationTests/corion/moduleHandler.sol8
-rw-r--r--test/compilationTests/corion/premium.sol4
-rw-r--r--test/compilationTests/corion/provider.sol12
-rw-r--r--test/compilationTests/corion/publisher.sol8
-rw-r--r--test/compilationTests/corion/schelling.sol6
-rw-r--r--test/compilationTests/corion/token.sol8
-rw-r--r--test/compilationTests/zeppelin/MultisigWallet.sol2
-rw-r--r--test/compilationTests/zeppelin/crowdsale/Crowdsale.sol4
-rw-r--r--test/compilationTests/zeppelin/crowdsale/RefundVault.sol8
-rw-r--r--test/compilationTests/zeppelin/lifecycle/Destructible.sol2
-rw-r--r--test/compilationTests/zeppelin/ownership/Claimable.sol4
-rw-r--r--test/compilationTests/zeppelin/ownership/Ownable.sol4
-rw-r--r--test/compilationTests/zeppelin/payment/PullPayment.sol2
-rw-r--r--test/compilationTests/zeppelin/token/VestedToken.sol2
-rw-r--r--test/contracts/AuctionRegistrar.cpp10
-rw-r--r--test/contracts/FixedFeeRegistrar.cpp4
-rw-r--r--test/contracts/Wallet.cpp4
-rwxr-xr-xtest/externalTests.sh4
-rw-r--r--test/libjulia/Inliner.cpp38
-rw-r--r--test/liblll/Compiler.cpp10
-rw-r--r--test/libsolidity/ASTJSON/address_payable.json560
-rw-r--r--test/libsolidity/ASTJSON/address_payable.sol11
-rw-r--r--test/libsolidity/ASTJSON/address_payable_legacy.json600
-rw-r--r--test/libsolidity/SMTChecker.cpp4
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp111
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp19
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp2
-rw-r--r--test/libsolidity/SolidityScanner.cpp5
-rw-r--r--test/libsolidity/StandardCompiler.cpp67
-rw-r--r--test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol15
-rw-r--r--test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol15
-rw-r--r--test/libsolidity/syntaxTests/array/length/parentheses.sol2
-rw-r--r--test/libsolidity/syntaxTests/conversion/allowed_conversion_to_bytes_array.sol9
-rw-r--r--test/libsolidity/syntaxTests/conversion/allowed_conversion_to_string.sol9
-rw-r--r--test/libsolidity/syntaxTests/conversion/explicit_conversion_from_storage_array_ref.sol10
-rw-r--r--test/libsolidity/syntaxTests/conversion/implicit_conversion_from_storage_array_ref.sol7
-rw-r--r--test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer1.sol10
-rw-r--r--test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer2.sol10
-rw-r--r--test/libsolidity/syntaxTests/dataLocations/memory_storage_data_location.sol12
-rw-r--r--test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol7
-rw-r--r--test/libsolidity/syntaxTests/multiline_comments.sol13
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/413_address_methods.sol2
-rw-r--r--test/libsolidity/syntaxTests/nameAndTypeResolution/535_address_overload_resolution.sol2
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_constant_payable.sol5
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_function_arguments_and_returns.sol4
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_in_struct.sol6
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_invalid_state_mutability.sol26
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_nonpayable.sol7
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable.sol7
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_constant.sol3
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_conversion.sol7
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_function_type.sol6
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_library.sol5
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_local.sol11
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_state_variable.sol8
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_struct.sol8
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_payable_type_expression.sol7
-rw-r--r--test/libsolidity/syntaxTests/parsing/address_public_payable_error.sol5
-rw-r--r--test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol2
-rw-r--r--test/libsolidity/syntaxTests/parsing/elemantary_non_address_payable_state_variable.sol29
-rw-r--r--test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_argument.sol29
-rw-r--r--test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_local.sol31
-rw-r--r--test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_return.sol29
-rw-r--r--test/libsolidity/syntaxTests/parsing/mapping_from_address_payable.sol5
-rw-r--r--test/libsolidity/syntaxTests/parsing/new_address_payable.sol5
-rw-r--r--test/libsolidity/syntaxTests/parsing/payable_accessor.sol2
-rw-r--r--test/libsolidity/syntaxTests/string/string_escapes.sol7
-rw-r--r--test/libsolidity/syntaxTests/string/string_new_line.sol9
-rw-r--r--test/libsolidity/syntaxTests/string/string_terminated_by_backslash.sol8
-rw-r--r--test/libsolidity/syntaxTests/string/string_unterminated.sol7
-rw-r--r--test/libsolidity/syntaxTests/string/string_unterminated_no_new_line.sol4
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_abi_decode.sol6
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_constant.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol20
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_members_in_contract.sol (renamed from test/libsolidity/syntaxTests/types/address_members_in_contract.sol)0
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol5
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol11
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_contract.sol (renamed from test/libsolidity/syntaxTests/types/address_to_contract.sol)0
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol6
-rw-r--r--test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol5
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol9
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_to_address.sol (renamed from test/libsolidity/syntaxTests/types/contract_to_address.sol)0
-rw-r--r--test/libsolidity/syntaxTests/types/address/contract_to_address_implicitly.sol (renamed from test/libsolidity/syntaxTests/types/contract_to_address_implicitly.sol)0
-rw-r--r--test/libsolidity/syntaxTests/types/address/literal_to_address.sol9
-rw-r--r--test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol8
-rw-r--r--test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol10
-rw-r--r--test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol7
-rw-r--r--test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol5
-rw-r--r--test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol7
-rw-r--r--test/libsolidity/syntaxTests/unicode_escape_literals.sol31
-rw-r--r--test/libsolidity/syntaxTests/unterminatedBlocks/one_dot.sol4
-rw-r--r--test/libsolidity/syntaxTests/unterminatedBlocks/one_dot_x.sol5
-rw-r--r--test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot.sol4
-rw-r--r--test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot_x.sol5
-rw-r--r--test/libsolidity/syntaxTests/upper_case_hex_literals.sol9
-rw-r--r--test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol2
-rw-r--r--test/tools/fuzzer.cpp71
225 files changed, 4786 insertions, 1184 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3e3d8c0a..f8e380d9 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -141,7 +141,7 @@ jobs:
build_x86_mac:
macos:
- xcode: "9.0"
+ xcode: "10.0.0"
environment:
TERM: xterm
steps:
@@ -179,14 +179,14 @@ jobs:
name: Check spelling
command: ~/.local/bin/codespell -S "*.enc,.git" -I ./scripts/codespell_whitelist.txt
- test_trailing_whitespace:
+ test_check_style:
docker:
- image: buildpack-deps:artful
steps:
- checkout
- run:
name: Check for trailing whitespace
- command: ./scripts/detect_trailing_whitespace.sh
+ command: ./scripts/check_style.sh
test_buglist:
docker:
@@ -236,7 +236,7 @@ jobs:
test_x86_mac:
macos:
- xcode: "9.0"
+ xcode: "10.0.0"
environment:
TERM: xterm
steps:
@@ -278,7 +278,7 @@ workflows:
build_all:
jobs:
- test_check_spelling: *build_on_tags
- - test_trailing_whitespace: *build_on_tags
+ - test_check_style: *build_on_tags
- test_buglist: *build_on_tags
- build_emscripten: *build_on_tags
- test_emscripten_solcjs:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 0cc0edec..c3caf86e 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -3,7 +3,7 @@ name: Bug Report
about: Bug reports about the Solidity Compiler.
---
-## Prerequisites
+<!--## Prerequisites
- First, many thanks for taking part in the community. We really appreciate that.
- 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.
@@ -12,12 +12,11 @@ about: Bug reports about the Solidity Compiler.
- [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.
-
-*Delete the above section and the instructions in the sections below before submitting*
+-->
## Description
-Please shortly describe the bug you have found, and what you expect instead.
+<!--Please shortly describe the bug you have found, and what you expect instead.-->
## Environment
@@ -28,6 +27,7 @@ Please shortly describe the bug you have found, and what you expect instead.
## Steps to Reproduce
+<!--
Please provide a *minimal* source code example to trigger the bug you have found.
Please also mention any command line flags that are necessary for triggering the bug.
Provide as much information as necessary to reproduce the bug.
@@ -36,3 +36,4 @@ Provide as much information as necessary to reproduce the bug.
// Some *minimal* Solidity source code to reproduce the bug.
// ...
```
+--> \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 6b98fb99..6702b62c 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -3,7 +3,7 @@ name: Feature Request
about: Solidity language or infrastructure feature requests.
---
-## Prerequisites
+<!--## 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.
@@ -14,24 +14,34 @@ about: Solidity language or infrastructure feature requests.
*Delete the above section and the instructions in the sections below before submitting*
+-->
+
## Abstract
+<!--
Please describe by example what problem you see in the current Solidity language
and reason about it.
+-->
## Motivation
+<!--
In this section you describe how you propose to address the problem you described earlier,
including by giving one or more exemplary source code snippets for demonstration.
+-->
## Specification
+<!--
The technical specification should describe the syntax and semantics of any new feature. The
specification should be detailed enough to allow any developer to implement the functionality.
+-->
## Backwards Compatibility
+<!--
All language changes that introduce backwards incompatibilities must include a section describing
these incompatibilities and their severity.
Please describe how you propose to deal with these incompatibilities.
+--> \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/general.md b/.github/ISSUE_TEMPLATE/general.md
index 2d277865..410b42e0 100644
--- a/.github/ISSUE_TEMPLATE/general.md
+++ b/.github/ISSUE_TEMPLATE/general.md
@@ -3,7 +3,7 @@ name: General Feedback
about: Any general feedback (neither feature request nor bug reports)
---
-## Prerequisites
+<!--## Prerequisites
- First, many thanks for taking part in the community. We really appreciate that.
- Read the [contributing guidelines](http://solidity.readthedocs.io/en/latest/contributing.html).
@@ -13,7 +13,9 @@ about: Any general feedback (neither feature request nor bug reports)
- Ensure the issue isn't already reported.
*Delete the above section and the instructions in the sections below before submitting*
-
+-->
## Description
+<!--
Please describe the purpose of your ticket.
+-->
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 6f544bc1..9734fe81 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,8 +1,9 @@
-### Your checklist for this pull request
+<!--### Your checklist for this pull request
Please review the [guidelines for contributing](http://solidity.readthedocs.io/en/latest/contributing.html) to this repository.
Please also note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms.
+-->
### Checklist
- [ ] Code compiles correctly
@@ -13,6 +14,9 @@ Please also note that this project is released with a [Contributor Code of Condu
- [ ] Used meaningful commit messages
### Description
+
+<!--
Please explain the changes you made here.
Thank you for your help!
+--> \ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f30872af..f2c84d20 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
-set(PROJECT_VERSION "0.4.25")
+set(PROJECT_VERSION "0.5.0")
project(solidity VERSION ${PROJECT_VERSION})
option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF)
diff --git a/Changelog.md b/Changelog.md
index 507c3ce1..2d6f518c 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -7,6 +7,7 @@ How to update your code:
* Make your fallback functions ``external``.
* Explicitly state the data location for all variables of struct, array or mapping types (including function parameters), e.g. change ``uint[] x = m_x`` to ``uint[] storage x = m_x``. Note that ``external`` functions require parameters with a data location of ``calldata``.
* Explicitly convert values of contract type to addresses before using an ``address`` member. Example: if ``c`` is a contract, change ``c.transfer(...)`` to ``address(c).transfer(...)``.
+ * Declare variables and especially function arguments as ``address payable``, if you want to call ``transfer`` on them.
Breaking Changes:
* ABI Encoder: Properly pad data from calldata (``msg.data`` and external function parameters). Use ``abi.encodePacked`` for unpadded encoding.
@@ -40,7 +41,8 @@ Breaking Changes:
* Name Resolver: Do not exclude public state variables when looking for conflicting declarations.
* Optimizer: Remove the no-op ``PUSH1 0 NOT AND`` sequence.
* Parser: Disallow trailing dots that are not followed by a number.
- * Parser: Remove ``constant`` as function state mutability modifer.
+ * Parser: Remove ``constant`` as function state mutability modifier.
+ * Parser: Disallow uppercase X in hex number literals
* Type Checker: Disallow assignments between tuples with different numbers of components. This was already the case in the experimental 0.5.0 mode.
* Type Checker: Disallow values for constants that are not compile-time constants. This was already the case in the experimental 0.5.0 mode.
* Type Checker: Disallow arithmetic operations for boolean variables.
@@ -63,6 +65,7 @@ Breaking Changes:
* Type Checker: Disallow "loose assembly" syntax entirely. This means that jump labels, jumps and non-functional instructions cannot be used anymore.
* Type System: Disallow explicit and implicit conversions from decimal literals to ``bytesXX`` types.
* Type System: Disallow explicit and implicit conversions from hex literals to ``bytesXX`` types of different size.
+ * Type System: Distinguish between payable and non-payable address types.
* View Pure Checker: Disallow ``msg.value`` in (or introducing it via a modifier to) a non-payable function.
* Remove obsolete ``std`` directory from the Solidity repository. This means accessing ``https://github.com/ethereum/solidity/blob/develop/std/*.sol`` (or ``https://github.com/ethereum/solidity/std/*.sol`` in Remix) will not be possible.
* References Resolver: Turn missing storage locations into an error. This was already the case in the experimental 0.5.0 mode.
@@ -71,10 +74,10 @@ Breaking Changes:
* Syntax Checker: Strictly require visibility specifier for functions. This was already the case in the experimental 0.5.0 mode.
* Syntax Checker: Disallow unary ``+``. This was already the case in the experimental 0.5.0 mode.
* Syntax Checker: Disallow single statement variable declaration inside if/while/for bodies that are not blocks.
- * View Pure Checker: Strictly enfore state mutability. This was already the case in the experimental 0.5.0 mode.
+ * View Pure Checker: Strictly enforce state mutability. This was already the case in the experimental 0.5.0 mode.
Language Features:
- * Genreal: Add ``staticcall`` to ``address``.
+ * General: 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.
@@ -82,9 +85,14 @@ Language Features:
* General: Allow ``mapping`` storage pointers as arguments and return values in all internal functions.
* General: Allow ``struct``s in interfaces.
* General: Provide access to the ABI decoder through ``abi.decode(bytes memory data, (...))``.
+ * General: Disallow zero length for fixed-size arrays.
+ * Parser: Accept the ``address payable`` type during parsing.
Compiler Features:
+ * Build System: Support for Mojave version of macOS added.
* C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods.
+ * Code Generator: ``CREATE2`` instruction has been updated to match EIP1014 (aka "Skinny CREATE2"). It also is accepted as part of Constantinople.
+ * Code Generator: ``EXTCODEHASH`` instruction has been added based on EIP1052.
* Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly.
* Type Checker: Show named argument in case of error.
* Type System: IntegerType is split into IntegerType and AddressType internally.
@@ -92,17 +100,16 @@ Compiler Features:
* Code Generator: Allocate and free local variables according to their scope.
* Removed ``pragma experimental "v0.5.0";``.
-Critical Bugfixes:
- * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types.
-
Bugfixes:
* Build System: Support versions of CVC4 linked against CLN instead of GMP. In case of compilation issues due to the experimental SMT solver support, the solvers can be disabled when configuring the project with CMake using ``-DUSE_CVC4=OFF`` or ``-DUSE_Z3=OFF``.
* Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum.
* Code Generator: Fix allocation of byte arrays (zeroed out too much memory).
* Code Generator: Properly handle negative number literals in ABIEncoderV2.
+ * Code Generator: Do not crash on using a length of zero for multidimensional fixed-size arrays.
* Commandline Interface: Correctly handle paths with backslashes on windows.
* Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions.
* Optimizer: Correctly estimate gas costs of constants for special cases.
+ * Optimizer: Fix simplification rule initialization bug that appeared on some emscripten platforms.
* References Resolver: Do not crash on using ``_slot`` and ``_offset`` suffixes on their own.
* References Resolver: Enforce ``storage`` as data location for mappings.
* References Resolver: Properly handle invalid references used together with ``_slot`` and ``_offset``.
@@ -115,13 +122,20 @@ Bugfixes:
* Type Checker: Consider fixed size arrays when checking for recursive structs.
* 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 Checker: Fix internal error when array index value is too large.
+ * Type Checker: Fix internal error for array type conversions.
* Type System: Allow arbitrary exponents for literals with a mantissa of zero.
* Parser: Fix incorrect source location for nameless parameters.
- * Parser: Treat unicode line endings as terminating strings and single-line comments.
+
+### 0.4.25 (2018-09-12)
+
+Important Bugfixes:
+ * Code Generator: Properly perform cleanup for exponentiation and non-256 bit types.
+ * Type Checker: Report error when using indexed structs in events with experimental ABIEncoderV2. This used to log wrong values.
+ * Type Checker: Report error when using structs in events without experimental ABIEncoderV2. This used to crash or log the wrong values.
+ * Parser: Consider all unicode line terminators (LF, VF, FF, CR, NEL, LS, PS) for single-line comments
+ and string literals. They are invalid in strings and will end comments.
* Parser: Disallow unterminated multi-line comments at the end of input.
* Parser: Treat ``/** /`` as unterminated multi-line comment.
@@ -223,7 +237,7 @@ Bugfixes:
Features:
* Code Generator: Assert that ``k != 0`` for ``mulmod(a, b, k)`` and ``addmod(a, b, k)`` as experimental 0.5.0 feature.
* Code Generator: Do not retain any gas in calls (except if EVM version is set to homestead).
- * Code Generator: Use ``STATICCALL`` opcode for calling ``view`` and ``pure`` functions as experimenal 0.5.0 feature.
+ * Code Generator: Use ``STATICCALL`` opcode for calling ``view`` and ``pure`` functions as experimental 0.5.0 feature.
* General: C99/C++-style scoping rules (instead of JavaScript function scoping) take effect as experimental v0.5.0 feature.
* General: Improved messaging when error spans multiple lines of a sourcefile
* General: Support and recommend using ``emit EventName();`` to call events explicitly.
diff --git a/README.md b/README.md
index dedd1ab7..7a448e8c 100644
--- a/README.md
+++ b/README.md
@@ -29,8 +29,10 @@ Instructions about how to build and install the Solidity compiler can be found i
A "Hello World" program in Solidity is of even less use than in other languages, but still:
```
+pragma solidity ^0.4.16;
+
contract HelloWorld {
- function f() pure returns (string memory) {
+ function helloWorld() external pure returns (string memory) {
return "Hello, World!";
}
}
diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst
new file mode 100644
index 00000000..9094000e
--- /dev/null
+++ b/docs/050-breaking-changes.rst
@@ -0,0 +1,413 @@
+********************************
+Solidity v0.5.0 Breaking Changes
+********************************
+
+This section highlights the main breaking changes introduced in Solidity
+version 0.5.0, along with the reasoning behind the changes and how to update
+affected code.
+For the full list check
+`the release changelog <https://github.com/ethereum/solidity/releases/tag/v0.5.0>`_.
+
+.. note::
+ Contracts compiled with Solidity v0.5.0 can still interface with contracts
+ and even libraries compiled with older versions without recompiling or
+ redeploying them. Changing the interfaces to include data locations and
+ visibility and mutability specifiers suffices.
+
+Semantic Only Changes
+=====================
+
+This section lists the changes that are semantic-only, thus potentially
+hiding new and different behavior in existing code.
+
+* Signed right shift now uses proper arithmetic shift, i.e. rounding towards
+ negative infinity, instead of rounding towards zero. Signed and unsigned
+ shift will have dedicated opcodes in Constantinople, and are emulated by
+ Solidity for the moment.
+
+* The ``continue`` statement in a ``do...while`` loop now jumps to the
+ condition, which is the common behavior in such cases. It used to jump to the
+ loop body. Thus, if the condition is false, the loop terminates.
+
+* The functions ``.call()``, ``.delegatecall()`` and ``.staticcall()`` do not
+ pad anymore when given a single ``bytes`` parameter.
+
+* Pure and view functions are now called using the opcode ``STATICCALL``
+ instead of ``CALL`` if the EVM version is Byzantium or later. This
+ disallows state changes on the EVM level.
+
+* The ABI encoder now properly pads byte arrays and strings from calldata
+ (``msg.data`` and external function parameters) when used in external
+ function calls and in ``abi.encode``. For unpadded encoding, use
+ ``abi.encodePacked``.
+
+* The ABI decoder reverts in the beginning of functions and in
+ ``abi.decode()`` if passed calldata is too short or points out of bounds.
+ Note that dirty higher order bits are still simply ignored.
+
+* Forward all available gas with external function calls starting from
+ Tangerine Whistle.
+
+Semantic and Syntactic Changes
+==============================
+
+This section highlights changes that affect syntax and semantics.
+
+* The functions ``.call()``, ``.delegatecall()``, ``staticcall()``,
+ ``keccak256()``, ``sha256()`` and ``ripemd160()`` now accept only a single
+ ``bytes`` argument. Moreover, the argument is not padded. This was changed to
+ make more explicit and clear how the arguments are concatenated. Change every
+ ``.call()`` (and family) to a ``.call("")`` and every ``.call(signature, a,
+ b, c)`` to use ``.call(abi.encodeWithSignature(signature, a, b, c))`` (the
+ last one only works for value types). Change every ``keccak256(a, b, c)`` to
+ ``keccak256(abi.encodePacked(a, b, c))``. Even though it is not a breaking
+ change, it is suggested that developers change
+ ``x.call(bytes4(keccak256("f(uint256)"), a, b)`` to
+ ``x.call(abi.encodeWithSignature("f(uint256)", a, b))``.
+
+* Functions ``.call()``, ``.delegatecall()`` and ``.staticcall()`` now return
+ ``(bool, bytes memory)`` to provide access to the return data. Change
+ ``bool success = otherContract.call("f")`` to ``(bool success, bytes memory
+ data) = otherContract.call("f")``.
+
+* Solidity now implements C99-style scoping rules for function local
+ variables, that is, variables can only be used after they have been
+ declared and only in the same or nested scopes. Variables declared in the
+ initialization block of a ``for`` loop are valid at any point inside the
+ loop.
+
+Explicitness Requirements
+=========================
+
+This section lists changes where the code now needs to be more explicit.
+For most of the topics the compiler will provide suggestions.
+
+* Explicit function visibility is now mandatory. Add ``public`` to every
+ function and constructor, and ``external`` to every fallback or interface
+ function that does not specify its visibility already.
+
+* Explicit data location for all variables of struct, array or mapping types is
+ now mandatory. This is also applied to function parameters and return
+ variables. For example, change ``uint[] x = m_x`` to ``uint[] storage x =
+ m_x``, and ``function f(uint[][] x)`` to ``function f(uint[][] memory x)``
+ where ``memory`` is the data location and might be replaced by ``storage`` or
+ ``calldata`` accordingly. Note that ``external`` functions require
+ parameters with a data location of ``calldata``.
+
+* Contract types do not include ``address`` members anymore in
+ order to separate the namespaces. Therefore, it is now necessary to
+ explicitly convert values of contract type to addresses before using an
+ ``address`` member. Example: if ``c`` is a contract, change
+ ``c.transfer(...)`` to ``address(c).transfer(...)``,
+ and ``c.balance`` to ``address(c).balance``.
+
+* The ``address`` type was split into ``address`` and ``address payable``,
+ where only ``address payable`` provides the ``transfer`` function. An
+ ``address payable`` can be directly converted to an ``address``, but the
+ other way around is not allowed. Converting ``address`` to ``address
+ payable`` is possible via conversion through ``uint160``. If ``c`` is a
+ contract, ``address(c)`` results in ``address payable`` only if ``c`` has a
+ payable fallback function. If you use the :ref:`withdraw pattern<withdrawal_pattern>`,
+ you most likely do not have to change your code because ``transfer``
+ is only used on ``msg.sender`` instead of stored addresses and ``msg.sender``
+ is an ``address payable``.
+
+* Conversions between ``bytesX`` and ``uintY`` of different size are now
+ disallowed due to ``bytesX`` padding on the right and ``uintY`` padding on
+ the left which may cause unexpected conversion results. The size must now be
+ adjusted within the type before the conversion. For example, you can convert
+ a ``bytes4`` (4 bytes) to a ``uint64`` (8 bytes) by first converting the
+ ``bytes4`` variable to ``bytes8`` and then to ``uint64``. You get the
+ opposite padding when converting through ``uint32``.
+
+* Using ``msg.value`` in non-payable functions (or introducing it via a
+ modifier) is disallowed as a security feature. Turn the function into
+ ``payable`` or create a new internal function for the program logic that
+ uses ``msg.value``.
+
+* For clarity reasons, the command line interface now requires ``-`` if the
+ standard input is used as source.
+
+Deprecated Elements
+===================
+
+This section lists changes that deprecate prior features or syntax. Note that
+many of these changes were already enabled in the experimental mode
+``v0.5.0``.
+
+Command Line and JSON Interfaces
+--------------------------------
+
+* The command line option ``--formal`` (used to generate Why3 output for
+ further formal verification) was deprecated and is now removed. A new
+ formal verification module, the SMTChecker, is enabled via ``pragma
+ experimental SMTChecker;``.
+
+* The command line option ``--julia`` was renamed to ``--yul`` due to the
+ renaming of the intermediate language ``Julia`` to ``Yul``.
+
+* The ``--clone-bin`` and ``--combined-json clone-bin`` command line options
+ were removed.
+
+* Remappings with empty prefix are disallowed.
+
+* The JSON AST fields ``constant`` and ``payable`` were removed. The
+ information is now present in the ``stateMutability`` field.
+
+Constructors
+------------
+
+* Constructors must now be defined using the ``constructor`` keyword.
+
+* Calling base constructors without parentheses is now disallowed.
+
+* Specifying base constructor arguments multiple times in the same inheritance
+ hierarchy is now disallowed.
+
+* Calling a constructor with arguments but with wrong argument count is now
+ disallowed. If you only want to specify an inheritance relation without
+ giving arguments, do not provide parentheses at all.
+
+Functions
+---------
+
+* Function ``callcode`` is now disallowed (in favor of ``delegatecall``). It
+ is still possible to use it via inline assembly.
+
+* ``suicide`` is now disallowed (in favor of ``selfdestruct``).
+
+* ``sha3`` is now disallowed (in favor of ``keccak256``).
+
+* ``throw`` is now disallowed (in favor of ``revert``, ``require`` and
+ ``assert``).
+
+Conversions
+-----------
+
+* Explicit and implicit conversions from decimal literals to ``bytesXX`` types
+ is now disallowed.
+
+* Explicit and implicit conversions from hex literals to ``bytesXX`` types
+ of different size is now disallowed.
+
+Literals and Suffixes
+---------------------
+
+* The unit denomination ``years`` is now disallowed due to complications and
+ confusions about leap years.
+
+* Trailing dots that are not followed by a number are now disallowed.
+
+* Combining hex numbers with unit denominations (e.g. ``0x1e wei``) is now
+ disallowed.
+
+* The prefix ``0X`` for hex numbers is disallowed, only ``0x`` is possible.
+
+Variables
+---------
+
+* Declaring empty structs is now disallowed for clarity.
+
+* The ``var`` keyword is now disallowed to favor explicitness.
+
+* Assignments between tuples with different number of components is now
+ disallowed.
+
+* Values for constants that are not compile-time constants are disallowed.
+
+* Multi-variable declarations with mismatching number of values are now
+ disallowed.
+
+* Uninitialized storage variables are now disallowed.
+
+* Empty tuple components are now disallowed.
+
+* Detecting cyclic dependencies in variables and structs is limited in
+ recursion to 256.
+
+* Fixed-size arrays with a length of zero are now disallowed.
+
+Syntax
+------
+
+* Using ``constant`` as function state mutability modifier is now disallowed.
+
+* Boolean expressions cannot use arithmetic operations.
+
+* The unary ``+`` operator is now disallowed.
+
+* Literals cannot anymore be used with ``abi.encodePacked`` without prior
+ conversion to an explicit type.
+
+* Empty return statements for functions with one or more return values are now
+ disallowed.
+
+* The "loose assembly" syntax is now disallowed entirely, that is, jump labels,
+ jumps and non-functional instructions cannot be used anymore. Use the new
+ ``while``, ``switch`` and ``if`` constructs instead.
+
+* Functions without implementation cannot use modifiers anymore.
+
+* Function types with named return values are now disallowed.
+
+* Single statement variable declarations inside if/while/for bodies that are
+ not blocks are now disallowed.
+
+* New keywords: ``calldata`` and ``constructor``.
+
+* New reserved keywords: ``alias``, ``apply``, ``auto``, ``copyof``,
+ ``define``, ``immutable``, ``implements``, ``macro``, ``mutable``,
+ ``override``, ``partial``, ``promise``, ``reference``, ``sealed``,
+ ``sizeof``, ``supports``, ``typedef`` and ``unchecked``.
+
+Example
+=======
+
+The following example shows a contract and its updated version for Solidity
+v0.5.0 with some of the changes listed in this section.
+
+Old version:
+
+::
+
+ // This will not compile
+ pragma solidity ^0.4.25;
+
+ contract OtherContract {
+ uint x;
+ function f(uint y) external {
+ x = y;
+ }
+ function() payable external {}
+ }
+
+ contract Old {
+ OtherContract other;
+ uint myNumber;
+
+ // Function mutability not provided, not an error.
+ function someInteger() internal returns (uint) { return 2; }
+
+ // Function visibility not provided, not an error.
+ // Function mutability not provided, not an error.
+ function f(uint x) returns (bytes) {
+ // Var is fine in this version.
+ var z = someInteger();
+ x += z;
+ // Throw is fine in this version.
+ if (x > 100)
+ throw;
+ bytes b = new bytes(x);
+ y = -3 >> 1;
+ // y == -1 (wrong, should be -2)
+ do {
+ x += 1;
+ if (x > 10) continue;
+ // 'Continue' causes an infinite loop.
+ } while (x < 11);
+ // Call returns only a Bool.
+ bool success = address(other).call("f");
+ if (!success)
+ revert();
+ else {
+ // Local variables could be declared after their use.
+ int y;
+ }
+ return b;
+ }
+
+ // No need for an explicit data location for 'arr'
+ function g(uint[] arr, bytes8 x, OtherContract otherContract) public {
+ otherContract.transfer(1 ether);
+
+ // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
+ // the first 4 bytes of x will be lost. This might lead to
+ // unexpected behavior since bytesX are right padded.
+ uint32 y = uint32(x);
+ myNumber += y + msg.value;
+ }
+ }
+
+New version:
+
+::
+
+ pragma solidity >0.4.99 <0.6.0;
+
+ contract OtherContract {
+ uint x;
+ function f(uint y) external {
+ x = y;
+ }
+ function() payable external {}
+ }
+
+ contract New {
+ OtherContract other;
+ uint myNumber;
+
+ // Function mutability must be specified.
+ function someInteger() internal pure returns (uint) { return 2; }
+
+ // Function visibility must be specified.
+ // Function mutability must be specified.
+ function f(uint x) public returns (bytes memory) {
+ // The type must now be explicitly given.
+ uint z = someInteger();
+ x += z;
+ // Throw is now disallowed.
+ require(x > 100);
+ int y = -3 >> 1;
+ // y == -2 (correct)
+ do {
+ x += 1;
+ if (x > 10) continue;
+ // 'Continue' jumps to the condition below.
+ } while (x < 11);
+
+ // Call returns (bool, bytes).
+ // Data location must be specified.
+ (bool success, bytes memory data) = address(other).call("f");
+ if (!success)
+ revert();
+ return data;
+ }
+
+ using address_make_payable for address;
+ // Data location for 'arr' must be specified
+ function g(uint[] memory arr, bytes8 x, OtherContract otherContract, address unknownContract) public payable {
+ // 'otherContract.transfer' is not provided.
+ // Since the code of 'OtherContract' is known and has the fallback
+ // function, address(otherContract) has type 'address payable'.
+ address(otherContract).transfer(1 ether);
+
+ // 'unknownContract.transfer' is not provided.
+ // 'address(unknownContract).transfer' is not provided
+ // since 'address(unknownContract)' is not 'address payable'.
+ // If the function takes an 'address' which you want to send
+ // funds to, you can convert it to 'address payable' via 'uint160'.
+ // Note: This is not recommended and the explicit type
+ // 'address payable' should be used whenever possible.
+ // To increase clarity, we suggest the use of a library for
+ // the conversion (provided after the contract in this example).
+ address payable addr = unknownContract.make_payable();
+ require(addr.send(1 ether));
+
+ // Since uint32 (4 bytes) is smaller than bytes8 (8 bytes),
+ // the conversion is not allowed.
+ // We need to convert to a common size first:
+ bytes4 x4 = bytes4(x); // Padding happens on the right
+ uint32 y = uint32(x4); // Conversion is consistent
+ // 'msg.value' cannot be used in a 'non-payable' function.
+ // We need to make the function payable
+ myNumber += y + msg.value;
+ }
+ }
+
+ // We can define a library for explicitly converting ``address``
+ // to ``address payable`` as a workaround.
+ library address_make_payable {
+ function make_payable(address x) internal pure returns (address payable) {
+ return address(uint160(x));
+ }
+ }
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index 92af8f0c..2c206dad 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -13,9 +13,9 @@ The Contract Application Binary Interface (ABI) is the standard way to interact
from outside the blockchain and for contract-to-contract interaction. Data is encoded according to its type,
as described in this specification. The encoding is not self describing and thus requires a schema in order to decode.
-We assume the interface functions of a contract are strongly typed, known at compilation time and static. No introspection mechanism will be provided. We assume that all contracts will have the interface definitions of any contracts they call available at compile-time.
+We assume the interface functions of a contract are strongly typed, known at compilation time and static. We assume that all contracts will have the interface definitions of any contracts they call available at compile-time.
-This specification does not address contracts whose interface is dynamic or otherwise known only at run-time. Should these cases become important they can be adequately handled as facilities built within the Ethereum ecosystem.
+This specification does not address contracts whose interface is dynamic or otherwise known only at run-time.
.. _abi_function_selector:
@@ -23,12 +23,12 @@ Function Selector
=================
The first four bytes of the call data for a function call specifies the function to be called. It is the
-first (left, high-order in big-endian) four bytes of the Keccak (SHA-3) hash of the signature of the function. The signature is defined as the canonical expression of the basic prototype, i.e.
+first (left, high-order in big-endian) four bytes of the Keccak-256 (SHA-3) hash of the signature of the function. The signature is defined as the canonical expression of the basic prototype without data location specifier, i.e.
the function name with the parenthesised list of parameter types. Parameter types are split by a single comma - no spaces are used.
.. note::
The return type of a function is not part of this signature. In :ref:`Solidity's function overloading <overload-function>` return types are not considered. The reason is to keep function call resolution context-independent.
- The JSON description of the ABI however contains both inputs and outputs. See (the :ref:`JSON ABI <abi_json>`)
+ The :ref:`JSON description of the ABI<abi_json>` however contains both inputs and outputs.
Argument Encoding
=================
@@ -78,20 +78,42 @@ Types can be combined to a tuple by enclosing them inside parentheses, separated
It is possible to form tuples of tuples, arrays of tuples and so on. It is also possible to form zero-tuples (where ``n == 0``).
-.. note::
- Solidity supports all the types presented above with the same names with the exception of tuples. The ABI tuple type is utilised for encoding Solidity ``structs``.
+Mapping Solidity to ABI types
+-----------------------------
+
+Solidity supports all the types presented above with the same names with the
+exception of tuples. On the other hand, some Solidity types are not supported
+by the ABI. The following table shows on the left column Solidity types that
+are not part of the ABI, and on the right column the ABI types that represent
+them.
+
++-------------------------------+-----------------------------------------------------------------------------+
+| Solidity | ABI |
++===============================+=============================================================================+
+|:ref:`address payable<address>`|``address`` |
++-------------------------------+-----------------------------------------------------------------------------+
+|:ref:`contract<contracts>` |``address`` |
++-------------------------------+-----------------------------------------------------------------------------+
+|:ref:`enum<enums>` |smallest ``uint`` type that is large enough to hold all values |
+| | |
+| |For example, an ``enum`` of 255 values or less is mapped to ``uint8`` and |
+| |an ``enum`` of 256 values is mapped to ``uint16``. |
++-------------------------------+-----------------------------------------------------------------------------+
+|:ref:`struct<structs>` |``tuple`` |
++-------------------------------+-----------------------------------------------------------------------------+
+
+Design Criteria for the Encoding
+================================
+
+The encoding is designed to have the following properties, which are especially useful if some arguments are nested arrays:
-Formal Specification of the Encoding
-====================================
+ 1. The number of reads necessary to access a value is at most the depth of the value inside the argument array structure, i.e. four reads are needed to retrieve ``a_i[k][l][r]``. In a previous version of the ABI, the number of reads scaled linearly with the total number of dynamic parameters in the worst case.
-We will now formally specify the encoding, such that it will have the following
-properties, which are especially useful if some arguments are nested arrays:
+ 2. The data of a variable or array element is not interleaved with other data and it is relocatable, i.e. it only uses relative "addresses".
-Properties:
- 1. The number of reads necessary to access a value is at most the depth of the value inside the argument array structure, i.e. four reads are needed to retrieve ``a_i[k][l][r]``. In a previous version of the ABI, the number of reads scaled linearly with the total number of dynamic parameters in the worst case.
-
- 2. The data of a variable or array element is not interleaved with other data and it is relocatable, i.e. it only uses relative "addresses"
+Formal Specification of the Encoding
+====================================
We distinguish static and dynamic types. Static types are encoded in-place and dynamic types are encoded at a separately allocated location after the current block.
@@ -190,7 +212,7 @@ Given the contract:
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract Foo {
function bar(bytes3[2] memory) public pure {}
@@ -383,6 +405,8 @@ Offset ``f`` points to the start of the content of the array ``[[1, 2], [3]]`` w
Offset ``g`` points to the start of the content of the array ``["one", "two", "three"]`` which is line 10 (320 bytes); thus ``g = 0x0000000000000000000000000000000000000000000000000000000000000140``.
+.. _abi_events:
+
Events
======
@@ -416,8 +440,8 @@ A function description is a JSON object with the fields:
* ``components``: used for tuple types (more below).
- ``outputs``: an array of objects similar to ``inputs``, can be omitted if function doesn't return anything;
-- ``stateMutability``: a string with one of the following values: ``pure`` (:ref:`specified to not read blockchain state <pure-functions>`), ``view`` (:ref:`specified to not modify the blockchain state <view-functions>`), ``nonpayable`` (function does not accept ether) and ``payable`` (function accepts ether);
-- ``payable``: ``true`` if function accepts ether, ``false`` otherwise;
+- ``stateMutability``: a string with one of the following values: ``pure`` (:ref:`specified to not read blockchain state <pure-functions>`), ``view`` (:ref:`specified to not modify the blockchain state <view-functions>`), ``nonpayable`` (function does not accept Ether) and ``payable`` (function accepts Ether);
+- ``payable``: ``true`` if function accepts Ether, ``false`` otherwise;
- ``constant``: ``true`` if function is either ``pure`` or ``view``, ``false`` otherwise.
``type`` can be omitted, defaulting to ``"function"``, likewise ``payable`` and ``constant`` can be omitted, both defaulting to ``false``.
@@ -428,7 +452,7 @@ Constructor and fallback function never have ``name`` or ``outputs``. Fallback f
The fields ``constant`` and ``payable`` are deprecated and will be removed in the future. Instead, the ``stateMutability`` field can be used to determine the same properties.
.. note::
- Sending non-zero ether to non-payable function will revert the transaction.
+ Sending non-zero Ether to non-payable function will revert the transaction.
An event description is a JSON object with fairly similar fields:
@@ -447,7 +471,7 @@ For example,
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract Test {
constructor() public { b = hex"12345678901234567890123456789012"; }
@@ -494,7 +518,7 @@ As an example, the code
::
- pragma solidity ^0.4.19;
+ pragma solidity >=0.4.19 <0.6.0;
pragma experimental ABIEncoderV2;
contract Test {
diff --git a/docs/assembly.rst b/docs/assembly.rst
index 2cbad06f..20fb0cd5 100644
--- a/docs/assembly.rst
+++ b/docs/assembly.rst
@@ -4,22 +4,25 @@ Solidity Assembly
.. index:: ! assembly, ! asm, ! evmasm
-Solidity defines an assembly language that can also be used without Solidity.
-This assembly language can also be used as "inline assembly" inside Solidity
-source code. We start with describing how to use inline assembly and how it
-differs from standalone assembly and then specify assembly itself.
+Solidity defines an assembly language that you can use without Solidity and also
+as "inline assembly" inside Solidity source code. This guide starts with describing
+how to use inline assembly, how it differs from standalone assembly, and
+specifies assembly itself.
.. _inline-assembly:
Inline Assembly
===============
-For more fine-grained control especially in order to enhance the language by writing libraries,
-it is possible to interleave Solidity statements with inline assembly in a language close
-to the one of the virtual machine. Due to the fact that the EVM is a stack machine, it is
-often hard to address the correct stack slot and provide arguments to opcodes at the correct
-point on the stack. Solidity's inline assembly tries to facilitate that and other issues
-arising when writing manual assembly by the following features:
+You can interleave Solidity statements with inline assembly in a language close
+to the one of the virtual machine. This gives you more fine-grained control,
+especially when you are enhancing the language by writing libraries.
+
+As the EVM is a stack machine, it is often hard to address the correct stack slot
+and provide arguments to opcodes at the correct point on the stack. Solidity's inline
+assembly helps you do this, and with other issues that arise when writing manual assembly.
+
+Inline assembly has the following features:
* functional-style opcodes: ``mul(1, add(2, 3))``
* assembly-local variables: ``let x := add(2, 3) let y := mload(0x40) x := add(x, y)``
@@ -29,28 +32,51 @@ arising when writing manual assembly by the following features:
* switch statements: ``switch x case 0 { y := mul(x, 2) } default { y := 0 }``
* function calls: ``function f(x) -> y { switch x case 0 { y := 1 } default { y := mul(x, f(sub(x, 1))) } }``
-We now want to describe the inline assembly language in detail.
-
.. warning::
Inline assembly is a way to access the Ethereum Virtual Machine
- at a low level. This discards several important safety
- features of Solidity.
+ at a low level. This bypasses several important safety
+ features and checks of Solidity. You should only use it for
+ tasks that need it, and only if you are confident with using it.
+
+Syntax
+------
+
+Assembly parses comments, literals and identifiers in the same way as Solidity, so you can use the
+usual ``//`` and ``/* */`` comments. Inline assembly is marked by ``assembly { ... }`` and inside
+these curly braces, you can use the following (see the later sections for more details):
+
+ - literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters)
+ - opcodes in functional style, e.g. ``add(1, mlod(0))``
+ - variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned)
+ - identifiers (assembly-local variables and externals if used as inline assembly), e.g. ``add(3, x)``, ``sstore(x_slot, 2)``
+ - assignments, e.g. ``x := add(y, 3)``
+ - blocks where local variables are scoped inside, e.g. ``{ let x := 3 { let y := add(x, 1) } }``
+
+The following features are only available for standalone assembly:
+
+ - direct stack control via ``dup1``, ``swap1``, ...
+ - direct stack assignments (in "instruction style"), e.g. ``3 =: x``
+ - labels, e.g. ``name:``
+ - jump opcodes
.. note::
- TODO: Write about how scoping rules of inline assembly are a bit different
- and the complications that arise when for example using internal functions
- of libraries. Furthermore, write about the symbols defined by the compiler.
+ Standalone assembly is supported for backwards compatibility but is not documented
+ here anymore.
+
+At the end of the ``assembly { ... }`` block, the stack must be balanced,
+unless you require it otherwise. If it is not balanced, the compiler generates
+a warning.
Example
-------
The following example provides library code to access the code of another contract and
-load it into a ``bytes`` variable. This is not possible at all with "plain Solidity" and the
-idea is that assembly libraries will be used to enhance the language in such ways.
+load it into a ``bytes`` variable. This is not possible with "plain Solidity" and the
+idea is that assembly libraries will be used to enhance the Solidity language.
.. code::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
library GetCode {
function at(address _addr) public view returns (bytes memory o_code) {
@@ -70,14 +96,12 @@ idea is that assembly libraries will be used to enhance the language in such way
}
}
-Inline assembly could also be beneficial in cases where the optimizer fails to produce
-efficient code. Please be aware that assembly is much more difficult to write because
-the compiler does not perform checks, so you should use it for complex things only if
-you really know what you are doing.
+Inline assembly is also beneficial in cases where the optimizer fails to produce
+efficient code, for example:
.. code::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
library VectorSum {
// This function is less efficient because the optimizer currently fails to
@@ -125,21 +149,7 @@ you really know what you are doing.
}
-Syntax
-------
-
-Assembly parses comments, literals and identifiers exactly as Solidity, so you can use the
-usual ``//`` and ``/* */`` comments. Inline assembly is marked by ``assembly { ... }`` and inside
-these curly braces, the following can be used (see the later sections for more details)
-
- - literals, i.e. ``0x123``, ``42`` or ``"abc"`` (strings up to 32 characters)
- - opcodes in functional style, e.g. ``add(1, mlod(0))``
- - labels, e.g. ``name:``
- - variable declarations, e.g. ``let x := 7``, ``let x := add(y, 3)`` or ``let x`` (initial value of empty (0) is assigned)
- - identifiers (labels or assembly-local variables and externals if used as inline assembly), e.g. ``jump(name)``, ``3 x add``
- - assignments (in "instruction style"), e.g. ``3 =: x``
- - assignments in functional style, e.g. ``x := add(y, 3)``
- - blocks where local variables are scoped inside, e.g. ``{ let x := 3 { let y := add(x, 1) } }``
+.. _opcodes:
Opcodes
-------
@@ -155,7 +165,7 @@ Opcodes marked with ``F``, ``H``, ``B`` or ``C`` are present since Frontier, Hom
Constantinople is still in planning and all instructions marked as such will result in an invalid instruction exception.
In the following, ``mem[a...b)`` signifies the bytes of memory starting at position ``a`` up to
-(excluding) position ``b`` and ``storage[p]`` signifies the storage contents at position ``p``.
+but not including position ``b`` and ``storage[p]`` signifies the storage contents at position ``p``.
The opcodes ``pushi`` and ``jumpdest`` cannot be used directly.
@@ -270,12 +280,16 @@ In the grammar, opcodes are represented as pre-defined identifiers.
+-------------------------+-----+---+-----------------------------------------------------------------+
| returndatacopy(t, f, s) | `-` | B | copy s bytes from returndata at position f to mem at position t |
+-------------------------+-----+---+-----------------------------------------------------------------+
+| extcodehash(a) | | C | code hash of address a |
++-------------------------+-----+---+-----------------------------------------------------------------+
| create(v, p, s) | | F | create new contract with code mem[p...(p+s)) and send v wei |
| | | | and return the new address |
+-------------------------+-----+---+-----------------------------------------------------------------+
| create2(v, n, p, s) | | C | create new contract with code mem[p...(p+s)) at address |
-| | | | keccak256(<address> . n . keccak256(mem[p...(p+s))) and send v |
-| | | | wei and return the new address |
+| | | | keccak256(0xff . self . n . keccak256(mem[p...(p+s))) |
+| | | | and send v wei and return the new address, where ``0xff`` is a |
+| | | | 8 byte value, ``self`` is the current contract's address |
+| | | | as a 20 byte value and ``n`` is a big-endian 256-bit value |
+-------------------------+-----+---+-----------------------------------------------------------------+
| call(g, a, v, in, | | F | call contract at address a with input mem[in...(in+insize)) |
| insize, out, outsize) | | | providing g gas and v wei and output area |
@@ -333,54 +347,55 @@ Literals
You can use integer constants by typing them in decimal or hexadecimal notation and an
appropriate ``PUSHi`` instruction will automatically be generated. The following creates code
to add 2 and 3 resulting in 5 and then computes the bitwise and with the string "abc".
+The final value is assigned to a local variable called ``x``.
Strings are stored left-aligned and cannot be longer than 32 bytes.
.. code::
- assembly { 2 3 add "abc" and }
+ assembly { let x := and("abc", add(3, 2)) }
+
Functional Style
-----------------
-You can type opcode after opcode in the same way they will end up in bytecode. For example
-adding ``3`` to the contents in memory at position ``0x80`` would be
+For a sequence of opcodes, it is often hard to see what the actual
+arguments for certain opcodes are. In the following example,
+``3`` is added to the contents in memory at position ``0x80``.
.. code::
3 0x80 mload add 0x80 mstore
-As it is often hard to see what the actual arguments for certain opcodes are,
-Solidity inline assembly also provides a "functional style" notation where the same code
-would be written as follows
+Solidity inline assembly has a "functional style" notation where the same code
+would be written as follows:
.. code::
mstore(0x80, add(mload(0x80), 3))
-Functional style expressions cannot use instructional style internally, i.e.
-``1 2 mstore(0x80, add)`` is not valid assembly, it has to be written as
-``mstore(0x80, add(2, 1))``. For opcodes that do not take arguments, the
-parentheses can be omitted.
+If you read the code from right to left, you end up with exactly the same
+sequence of constants and opcodes, but it is much clearer where the
+values end up.
-Note that the order of arguments is reversed in functional-style as opposed to the instruction-style
-way. If you use functional-style, the first argument will end up on the stack top.
+If you care about the exact stack layout, just note that the
+syntactically first argument for a function or opcode will be put at the
+top of the stack.
+Access to External Variables, Functions and Libraries
+-----------------------------------------------------
-Access to External Variables and Functions
-------------------------------------------
-
-Solidity variables and other identifiers can be accessed by simply using their name.
-For memory variables, this will push the address and not the value onto the
-stack. Storage variables are different: Values in storage might not occupy a
-full storage slot, so their "address" is composed of a slot and a byte-offset
+You can access Solidity variables and other identifiers by using their name.
+For variables stored in the memory data location, this pushes the address, and not the value
+onto the stack. Variables stored in the storage data location are different, as they might not
+occupy a full storage slot, so their "address" is composed of a slot and a byte-offset
inside that slot. To retrieve the slot pointed to by the variable ``x``, you
-used ``x_slot`` and to retrieve the byte-offset you used ``x_offset``.
+use ``x_slot``, and to retrieve the byte-offset you use ``x_offset``.
-In assignments (see below), we can even use local Solidity variables to assign to.
+Local Solidity variables are available for assignments, for example:
.. code::
- pragma solidity ^0.4.11;
+ pragma solidity >=0.4.11 <0.6.0;
contract C {
uint b;
@@ -391,7 +406,7 @@ In assignments (see below), we can even use local Solidity variables to assign t
}
}
-.. note::
+.. warning::
If you access variables of a type that spans less than 256 bits
(for example ``uint64``, ``address``, ``bytes16`` or ``byte``),
you cannot make any assumptions about bits not part of the
@@ -419,7 +434,7 @@ be just ``0``, but it can also be a complex functional-style expression.
.. code::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function f(uint x) public view returns (uint b) {
@@ -443,26 +458,19 @@ Assignments are possible to assembly-local variables and to function-local
variables. Take care that when you assign to variables that point to
memory or storage, you will only change the pointer and not the data.
-There are two kinds of assignments: functional-style and instruction-style.
-For functional-style assignments (``variable := value``), you need to provide a value in a
-functional-style expression that results in exactly one stack value
-and for instruction-style (``=: variable``), the value is just taken from the stack top.
-For both ways, the colon points to the name of the variable. The assignment
-is performed by replacing the variable's value on the stack by the new value.
+Variables can only be assigned expressions that result in exactly one value.
+If you want to assign the values returned from a function that has
+multiple return parameters, you have to provide multiple variables.
.. code::
{
- let v := 0 // functional-style assignment as part of variable declaration
+ let v := 0
let g := add(v, 2)
- sload(10)
- =: v // instruction style assignment, puts the result of sload(10) into v
+ function f() -> a, b { }
+ let c, d := f()
}
-.. note::
- Instruction-style assignment is deprecated.
-
-
If
--
@@ -579,12 +587,9 @@ Things to Avoid
Inline assembly might have a quite high-level look, but it actually is extremely
low-level. Function calls, loops, ifs and switches are converted by simple
rewriting rules and after that, the only thing the assembler does for you is re-arranging
-functional-style opcodes, managing jump labels, counting stack height for
+functional-style opcodes, counting stack height for
variable access and removing stack slots for assembly-local variables when the end
-of their block is reached. Especially for those two last cases, it is important
-to know that the assembler only counts stack height from top to bottom, not
-necessarily following control flow. Furthermore, operations like swap will only
-swap the contents of the stack but not the location of variables.
+of their block is reached.
Conventions in Solidity
-----------------------
@@ -600,6 +605,8 @@ first.
Solidity manages memory in a very simple way: There is a "free memory pointer"
at position ``0x40`` in memory. If you want to allocate memory, just use the memory
starting from where this pointer points at and update it accordingly.
+There is no guarantee that the memory has not been used before and thus
+you cannot assume that its contents are zero bytes.
There is no built-in mechanism to release or free allocated memory.
Here is an assembly snippet that can be used for allocating memory::
@@ -618,10 +625,10 @@ of the free memory pointer.
Elements in memory arrays in Solidity always occupy multiples of 32 bytes (yes, this is
even true for ``byte[]``, but not for ``bytes`` and ``string``). Multi-dimensional memory
arrays are pointers to memory arrays. The length of a dynamic array is stored at the
-first slot of the array and then only the array elements follow.
+first slot of the array and followed by the array elements.
.. warning::
- Statically-sized memory arrays do not have a length field, but it will be added soon
+ Statically-sized memory arrays do not have a length field, but it might be added later
to allow better convertibility between statically- and dynamically-sized arrays, so
please do not rely on that.
@@ -656,7 +663,7 @@ Scoping: An identifier that is declared (label, variable, function, assembly)
is only visible in the block where it was declared (including nested blocks
inside the current block). It is not legal to access local variables across
function borders, even if they would be in scope. Shadowing is not allowed.
-Local variables cannot be accessed before they were declared, but labels,
+Local variables cannot be accessed before they were declared, but
functions and assemblies can. Assemblies are special blocks that are used
for e.g. returning runtime code or creating contracts. No identifier from an
outer assembly is visible in a sub-assembly.
@@ -667,7 +674,7 @@ Whenever a local variable is referenced, the code generator needs
to know its current relative position in the stack and thus it needs to
keep track of the current so-called stack height. Since all local variables
are removed at the end of a block, the stack height before and after the block
-should be the same. If this is not the case, a warning is issued.
+should be the same. If this is not the case, compilation fails.
Using ``switch``, ``for`` and functions, it should be possible to write
complex code without using ``jump`` or ``jumpi`` manually. This makes it much
@@ -684,7 +691,7 @@ Example:
We will follow an example compilation from Solidity to assembly.
We consider the runtime bytecode of the following Solidity program::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function f(uint x) public pure returns (uint y) {
diff --git a/docs/bugs.json b/docs/bugs.json
index 980b3897..28c0fe62 100644
--- a/docs/bugs.json
+++ b/docs/bugs.json
@@ -12,7 +12,7 @@
"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",
+ "fixed": "0.4.25",
"severity": "very low",
"check": {"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"}
},
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index 96cc3c5c..0318ac89 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -515,6 +515,10 @@
],
"released": "2018-05-16"
},
+ "0.4.25": {
+ "bugs": [],
+ "released": "2018-09-12"
+ },
"0.4.3": {
"bugs": [
"ExpExponentCleanup",
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst
index 6b061bf7..84c18936 100644
--- a/docs/common-patterns.rst
+++ b/docs/common-patterns.rst
@@ -13,11 +13,11 @@ Withdrawal from Contracts
The recommended method of sending funds after an effect
is using the withdrawal pattern. Although the most intuitive
method of sending Ether, as a result of an effect, is a
-direct ``send`` call, this is not recommended as it
+direct ``transfer`` call, this is not recommended as it
introduces a potential security risk. You may read
more about this on the :ref:`security_considerations` page.
-This is an example of the withdrawal pattern in practice in
+The following is an example of the withdrawal pattern in practice in
a contract where the goal is to send the most money to the
contract in order to become the "richest", inspired by
`King of the Ether <https://www.kingoftheether.com/>`_.
@@ -28,7 +28,7 @@ become the new richest.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract WithdrawalContract {
address public richest;
@@ -65,10 +65,10 @@ This is as opposed to the more intuitive sending pattern:
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract SendContract {
- address public richest;
+ address payable public richest;
uint public mostSent;
constructor() public payable {
@@ -130,7 +130,7 @@ restrictions highly readable.
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract AccessRestriction {
// These will be assigned at the construction
@@ -282,7 +282,7 @@ function finishes.
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract StateMachine {
enum Stages {
diff --git a/docs/contracts.rst b/docs/contracts.rst
index 8fd1c89e..faef3fc2 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -23,12 +23,12 @@ Contracts can be created "from outside" via Ethereum transactions or from within
IDEs, such as `Remix <https://remix.ethereum.org/>`_, make the creation process seamless using UI elements.
Creating contracts programmatically on Ethereum is best done via using the JavaScript API `web3.js <https://github.com/ethereum/web3.js>`_.
-As of today it has a method called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_
+It has a function 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.
-A constructor is optional. Only one constructor is allowed, and this means
+A constructor is optional. Only one constructor is allowed, which means
overloading is not supported.
.. index:: constructor;arguments
@@ -42,7 +42,7 @@ This means that cyclic creation dependencies are impossible.
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract OwnedToken {
// TokenCreator is a contract type that is defined below.
@@ -72,7 +72,7 @@ This means that cyclic creation dependencies are impossible.
function changeName(bytes32 newName) public {
// Only the creator can alter the name --
// the comparison is possible since contracts
- // are implicitly convertible to addresses.
+ // are explicitly convertible to addresses.
if (msg.sender == address(creator))
name = newName;
}
@@ -80,11 +80,11 @@ This means that cyclic creation dependencies are impossible.
function transfer(address newOwner) public {
// Only the current owner can transfer the token.
if (msg.sender != owner) return;
+
// We also want to ask the creator if the transfer
// is fine. Note that this calls a function of the
// contract defined below. If the call fails (e.g.
- // due to out-of-gas), the execution here stops
- // immediately.
+ // due to out-of-gas), the execution also fails here.
if (creator.isTokenTransferOK(owner, newOwner))
owner = newOwner;
}
@@ -102,7 +102,7 @@ This means that cyclic creation dependencies are impossible.
return new OwnedToken(name);
}
- function changeName(OwnedToken tokenAddress, bytes32 name) public {
+ function changeName(OwnedToken tokenAddress, bytes32 name) public {
// Again, the external type of `tokenAddress` is
// simply `address`.
tokenAddress.changeName(name);
@@ -162,7 +162,7 @@ For state variables, ``external`` is not possible.
.. note::
Everything that is inside a contract is visible to
- all external observers. Making something ``private``
+ all observers external to the blockchain. Making something ``private``
only prevents other contracts from accessing and modifying
the information, but it will still be visible to the
whole world outside of the blockchain.
@@ -173,7 +173,7 @@ return parameter list for functions.
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function f(uint a) private pure returns (uint b) { return a + 1; }
@@ -187,7 +187,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
uint private data;
@@ -231,7 +231,7 @@ when they are declared.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
uint public data = 42;
@@ -246,12 +246,12 @@ when they are declared.
The getter functions have external visibility. If the
symbol is accessed internally (i.e. without ``this.``),
-it is evaluated as a state variable. If it is accessed externally
-(i.e. with ``this.``), it is evaluated as a function.
+it evaluates to a state variable. If it is accessed externally
+(i.e. with ``this.``), it evaluates to a function.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
uint public data;
@@ -261,7 +261,7 @@ it is evaluated as a state variable. If it is accessed externally
}
}
-If you have a `public` state variable of array type, then you can only retrieve
+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
@@ -270,7 +270,8 @@ to write a function, for example:
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
+
contract arrayExample {
// public state variable
uint[] public myArray;
@@ -295,7 +296,7 @@ The next example is more complex:
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Complex {
struct Data {
@@ -330,11 +331,11 @@ inheritable properties of contracts and may be overridden by derived contracts.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract owned {
constructor() public { owner = msg.sender; }
- address owner;
+ address payable owner;
// This contract only defines a modifier but does not use
// it: it will be used in derived contracts.
@@ -438,7 +439,7 @@ State variables can be declared as ``constant``. In this case, they have to be
assigned from an expression which is a constant at compile time. Any expression
that accesses storage, blockchain data (e.g. ``now``, ``address(this).balance`` or
``block.number``) or
-execution data (``msg.value`` or ``gasleft()``) or make calls to external contracts are disallowed. Expressions
+execution data (``msg.value`` or ``gasleft()``) or makes calls to external contracts is disallowed. Expressions
that might have a side-effect on memory allocation are allowed, but those that
might have a side-effect on other memory objects are not. The built-in functions
``keccak256``, ``sha256``, ``ripemd160``, ``ecrecover``, ``addmod`` and ``mulmod``
@@ -456,7 +457,7 @@ value types and strings.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
uint constant x = 32**22 + 8;
@@ -483,7 +484,8 @@ Functions can be declared ``view`` in which case they promise not to modify the
.. note::
If the compiler's EVM target is Byzantium or newer (default) the opcode
- ``STATICCALL`` is used.
+ ``STATICCALL`` is used for ``view`` functions which enforces the state
+ to stay unmodified as part of the EVM execution.
The following statements are considered modifying the state:
@@ -498,7 +500,7 @@ The following statements are considered modifying the state:
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract C {
function f(uint a, uint b) public view returns (uint) {
@@ -510,7 +512,7 @@ The following statements are considered modifying the state:
``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0.
.. note::
- Getter methods are marked ``view``.
+ Getter methods are automatically marked ``view``.
.. note::
Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode
@@ -530,7 +532,8 @@ Pure Functions
Functions can be declared ``pure`` in which case they promise not to read from or modify the state.
.. note::
- If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used.
+ If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used,
+ which does not guarantee that the state is not read, but at least that it is not modified.
In addition to the list of state modifying statements explained above, the following are considered reading from the state:
@@ -542,7 +545,7 @@ In addition to the list of state modifying statements explained above, the follo
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract C {
function f(uint a, uint b) public pure returns (uint) {
@@ -562,7 +565,6 @@ In addition to the list of state modifying statements explained above, the follo
It is not possible to prevent functions from reading the state at the level
of the EVM, it is only possible to prevent them from writing to the state
(i.e. only ``view`` can be enforced at the EVM level, ``pure`` can not).
- It is a non-circumventable runtime checks done by the EVM.
.. warning::
Before version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state.
@@ -571,9 +573,6 @@ In addition to the list of state modifying statements explained above, the follo
not do state-changing operations, but it cannot check that the contract that will be called
at runtime is actually of that type.
-.. warning::
- Before version 0.5.0 the compiler did not enforce that ``view`` is not writing the state.
-
.. index:: ! fallback function, function;fallback
.. _fallback-function:
@@ -609,6 +608,12 @@ Like any function, the fallback function can execute complex operations as long
any payload supplied with the call.
.. warning::
+ The fallback function is also executed if the caller meant to call
+ a function that is not available. If you want to implement the fallback
+ function only to receive ether, you should add a check
+ like ``require(msg.data.length == 0)`` to prevent invalid calls.
+
+.. warning::
Contracts that receive Ether directly (without a function call, i.e. using ``send`` or ``transfer``)
but do not define a fallback function
throw an exception, sending back the Ether (this was different
@@ -625,7 +630,7 @@ Like any function, the fallback function can execute complex operations as long
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract Test {
// This function is called for all messages sent to
@@ -650,9 +655,14 @@ Like any function, the fallback function can execute complex operations as long
require(success);
// results in test.x becoming == 1.
+ // address(test) will not allow to call ``send`` directly, since ``test`` has no payable
+ // fallback function. It has to be converted to the ``address payable`` type via an
+ // intermediate conversion to ``uint160`` to even allow calling ``send`` on it.
+ address payable testPayable = address(uint160(address(test)));
+
// If someone sends ether to that contract,
// the transfer will fail, i.e. this returns false here.
- return address(test).send(2 ether);
+ return testPayable.send(2 ether);
}
}
@@ -671,7 +681,7 @@ The following example shows overloading of the function
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract A {
function f(uint _in) public pure returns (uint out) {
@@ -689,7 +699,7 @@ externally visible functions differ by their Solidity types but not by their ext
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
// This will not compile
contract A {
@@ -722,7 +732,7 @@ candidate, resolution fails.
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract A {
function f(uint8 _in) public pure returns (uint8 out) {
@@ -746,43 +756,64 @@ converted to ``uint8``.
Events
******
-Events allow the convenient usage of the EVM logging facilities,
-which in turn can be used to "call" JavaScript callbacks in the user interface
-of a dapp, which listen for these events.
+Solidity events give an abstraction on top of the EVM's logging functionality.
+Applications can subscribe and listen to these events through the RPC interface of an Ethereum client.
-Events are
-inheritable members of contracts. When they are called, they cause the
+Events are inheritable members of contracts. When you call them, they cause the
arguments to be stored in the transaction's log - a special data structure
-in the blockchain. These logs are associated with the address of
-the contract and will be incorporated into the blockchain
-and stay there as long as a block is accessible (forever as of
-Frontier and Homestead, but this might change with Serenity). Log and
-event data is not accessible from within contracts (not even from
-the contract that created them).
-
-SPV proofs for logs are possible, so if an external entity supplies
-a contract with such a proof, it can check that the log actually
-exists inside the blockchain. But be aware that block headers have to be supplied because
-the contract can only see the last 256 block hashes.
-
-Up to three parameters can
-receive the attribute ``indexed`` which will cause the respective arguments
-to be stored in a special data structure as so-called "topics", which allows them to be searched for,
-for example when filtering a sequence of blocks for certain events. Events can always
-be filtered by the address of the contract that emitted the event. Also,
-the hash of the signature of the event is one of the topics except if you
-declared the event with ``anonymous`` specifier. This means that it is
-not possible to filter for specific anonymous events by name.
+in the blockchain. These logs are associated with the address of the contract,
+are incorporated into the blockchain, and stay there as long as a block is
+accessible (forever as of the Frontier and Homestead releases, but this might
+change with Serenity). The Log and its event data is not accessible from within
+contracts (not even from the contract that created them).
+
+It is possible to request a simple payment verification (SPV) for logs, so if
+an external entity supplies a contract with such a verification, it can check
+that the log actually exists inside the blockchain. You have to supply block headers
+because the contract can only see the last 256 block hashes.
+
+You can add the attribute ``indexed`` to up to three parameters which adds them
+to a special data structure known as :ref:`"topics" <abi_events>` instead of
+the data part of the log. If you use arrays (including ``string`` and ``bytes``)
+as indexed arguments, its Keccak-256 hash is stored as a topic instead, this is
+because a topic can only hold a single word (32 bytes).
+
+All parameters without the ``indexed`` attribute are :ref:`ABI-encoded <ABI>`
+into the data part of the log.
+
+Topics allow you to search for events, for example when filtering a sequence of
+blocks for certain events. You can also filter events by the address of the
+contract that emitted the event.
+
+For example, the code below uses the web3.js ``subscribe("logs")``
+`method <https://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-logs>`_ to filter
+logs that match a topic with a certain address value:
+
+.. code-block:: javascript
+
+ var options = {
+ fromBlock: 0,
+ address: web3.eth.defaultAccount,
+ topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null]
+ };
+ web3.eth.subscribe('logs', options, function (error, result) {
+ if (!error)
+ console.log(result);
+ })
+ .on("data", function (log) {
+ console.log(log);
+ })
+ .on("changed", function (log) {
+ });
-If arrays (including ``string`` and ``bytes``) are used as indexed arguments, the
-Keccak-256 hash of it is stored as topic instead. This is because a topic
-can only hold a single word (32 bytes).
-All non-indexed arguments will be :ref:`ABI-encoded <ABI>` into the data part of the log.
+The hash of the signature of the event is one of the topics, except if you
+declared the event with the ``anonymous`` specifier. This means that it is
+not possible to filter for specific anonymous events by name.
::
- pragma solidity ^0.4.21;
+ pragma solidity >=0.4.21 <0.6.0;
contract ClientReceipt {
event Deposit(
@@ -801,7 +832,7 @@ All non-indexed arguments will be :ref:`ABI-encoded <ABI>` into the data part of
}
}
-The use in the JavaScript API would be as follows:
+The use in the JavaScript API is as follows:
::
@@ -813,19 +844,35 @@ The use in the JavaScript API would be as follows:
// watch for changes
event.watch(function(error, result){
- // result will contain various information
- // including the arguments given to the `Deposit`
- // call.
+ // result contains non-indexed arguments and topics
+ // given to the `Deposit` call.
if (!error)
console.log(result);
});
+
// Or pass a callback to start watching immediately
var event = clientReceipt.Deposit(function(error, result) {
if (!error)
console.log(result);
});
+The output of the above looks like the following (trimmed):
+
+.. code-block:: json
+
+ {
+ "returnValues": {
+ "_from": "0x1111…FFFFCCCC",
+ "_id": "0x50…sd5adb20",
+ "_value": "0x420042"
+ },
+ "raw": {
+ "data": "0x7f…91385",
+ "topics": ["0xfd4…b4ead7", "0x7f…1a91385"]
+ }
+ }
+
.. index:: ! log
Low-Level Interface to Logs
@@ -839,7 +886,7 @@ as topics. The event call above can be performed in the same way as
::
- pragma solidity ^0.4.10;
+ pragma solidity >=0.4.10 <0.6.0;
contract C {
function f() public payable {
@@ -887,11 +934,11 @@ Details are given in the following example.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract owned {
constructor() public { owner = msg.sender; }
- address owner;
+ address payable owner;
}
// Use `is` to derive from another contract. Derived
@@ -959,11 +1006,11 @@ Note that above, we call ``mortal.kill()`` to "forward" the
destruction request. The way this is done is problematic, as
seen in the following example::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract owned {
constructor() public { owner = msg.sender; }
- address owner;
+ address payable owner;
}
contract mortal is owned {
@@ -988,11 +1035,11 @@ derived override, but this function will bypass
``Base1.kill``, basically because it does not even know about
``Base1``. The way around this is to use ``super``::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract owned {
constructor() public { owner = msg.sender; }
- address owner;
+ address payable owner;
}
contract mortal is owned {
@@ -1038,10 +1085,8 @@ 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.
+After the constructor has run, the final code of the contract is returned. The deployment of
+the code costs additional gas linear to the length of the code.
Constructor functions can be either ``public`` or ``internal``. If there is no
constructor, the contract will assume the default constructor, which is
@@ -1049,7 +1094,7 @@ equivalent to ``constructor() public {}``. For example:
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract A {
uint public a;
@@ -1066,7 +1111,8 @@ equivalent to ``constructor() public {}``. For example:
A constructor set as ``internal`` causes the contract to be marked as :ref:`abstract <abstract-contract>`.
.. warning ::
- Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. This syntax was deprecated and is not allowed anymore in version 0.5.0.
+ Prior to version 0.4.22, constructors were defined as functions with the same name as the contract.
+ This syntax was deprecated and is not allowed anymore in version 0.5.0.
.. index:: ! base;constructor
@@ -1078,7 +1124,7 @@ The constructors of all the base contracts will be called following the
linearization rules explained below. If the base constructors have arguments,
derived contracts need to specify all of them. This can be done in two ways::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract Base {
uint x;
@@ -1096,7 +1142,7 @@ derived contracts need to specify all of them. This can be done in two ways::
}
One way is directly in the inheritance list (``is Base(7)``). The other is in
-the way a modifier would be invoked as part of the header of
+the way a modifier is invoked as part of
the derived constructor (``Base(_y * _y)``). The first way to
do it is more convenient if the constructor argument is a
constant and defines the behaviour of the contract or
@@ -1106,7 +1152,7 @@ derived contract. Arguments have to be given either in the
inheritance list or in modifier-style in the derived constructor.
Specifying arguments in both places is an error.
-If a derived contract doesn't specify the arguments to all of its base
+If a derived contract does not specify the arguments to all of its base
contracts' constructors, it will be abstract.
.. index:: ! inheritance;multiple, ! linearization, ! C3 linearization
@@ -1119,7 +1165,7 @@ Multiple Inheritance and Linearization
Languages that allow multiple inheritance have to deal with
several problems. One is the `Diamond Problem <https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem>`_.
Solidity is similar to Python in that it uses "`C3 Linearization <https://en.wikipedia.org/wiki/C3_linearization>`_"
-to force a specific order in the DAG of base classes. This
+to force a specific order in the directed acyclic graph (DAG) of base classes. This
results in the desirable property of monotonicity but
disallows some inheritance graphs. Especially, the order in
which the base classes are given in the ``is`` directive is
@@ -1137,7 +1183,7 @@ error "Linearization of inheritance graph impossible".
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract X {}
contract A is X {}
@@ -1168,7 +1214,7 @@ Abstract Contracts
Contracts are marked as abstract when at least one of their functions lacks an implementation as in the following example (note that the function declaration header is terminated by ``;``)::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Feline {
function utterance() public returns (bytes32);
@@ -1176,7 +1222,7 @@ Contracts are marked as abstract when at least one of their functions lacks an i
Such contracts cannot be compiled (even if they contain implemented functions alongside non-implemented functions), but they can be used as base contracts::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Feline {
function utterance() public returns (bytes32);
@@ -1205,42 +1251,48 @@ Abstract contracts are useful in the same way that defining methods in an interf
.. index:: ! contract;interface, ! interface contract
+.. _interfaces:
+
**********
Interfaces
**********
Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions:
-- Cannot inherit other contracts or interfaces.
+- They cannot inherit other contracts or interfaces.
- All declared functions must be external.
-- Cannot define constructor.
-- Cannot define variables.
-- Cannot define structs.
+- They cannot declare a constructor.
+- They cannot declare state variables.
Some of these restrictions might be lifted in the future.
Interfaces are basically limited to what the Contract ABI can represent, and the conversion between the ABI and
-an Interface should be possible without any information loss.
+an interface should be possible without any information loss.
Interfaces are denoted by their own keyword:
::
- pragma solidity ^0.4.11;
+ pragma solidity >=0.4.11 <0.6.0;
interface Token {
+ enum TokenType { Fungible, NonFungible }
+ struct Coin { string obverse; string reverse; }
function transfer(address recipient, uint amount) external;
}
Contracts can inherit interfaces as they would inherit other contracts.
+Types defined inside interfaces and other contract-like structures
+can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``.
+
.. index:: ! library, callcode, delegatecall
.. _libraries:
-************
+*********
Libraries
-************
+*********
Libraries are similar to contracts, but their purpose is that they are deployed
only once at a specific address and their code is reused using the ``DELEGATECALL``
@@ -1254,7 +1306,14 @@ would have no way to name them, otherwise). Library functions can only be
called directly (i.e. without the use of ``DELEGATECALL``) if they do not modify
the state (i.e. if they are ``view`` or ``pure`` functions),
because libraries are assumed to be stateless. In particular, it is
-not possible to destroy a library unless Solidity's type system is circumvented.
+not possible to destroy a library.
+
+.. note::
+ Until version 0.4.20, it was possible to destroy libraries by
+ circumventing Solidity's type system. Starting from that version,
+ libraries contain a :ref:`mechanism<call-protection>` that
+ disallows state-modifying functions
+ to be called directly (i.e. without ``DELEGATECALL``).
Libraries can be seen as implicit base contracts of the contracts that use them.
They will not be explicitly visible in the inheritance hierarchy, but calls
@@ -1270,13 +1329,13 @@ contract, and a regular ``JUMP`` call will be used instead of a ``DELEGATECALL``
.. index:: using for, set
-The following example illustrates how to use libraries (but
+The following example illustrates how to use libraries (but manual method
be sure to check out :ref:`using for <using-for>` for a
more advanced example to implement a set).
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
library Set {
// We define a new struct datatype that will be used to
@@ -1338,7 +1397,7 @@ parameters and in any position.
The calls to ``Set.contains``, ``Set.insert`` and ``Set.remove``
are all compiled as calls (``DELEGATECALL``) to an external
-contract/library. If you use libraries, take care that an
+contract/library. If you use libraries, be aware that an
actual external function call is performed.
``msg.sender``, ``msg.value`` and ``this`` will retain their values
in this call, though (prior to Homestead, because of the use of ``CALLCODE``, ``msg.sender`` and
@@ -1350,7 +1409,7 @@ custom types without the overhead of external function calls:
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
library BigInt {
struct bigint {
@@ -1416,6 +1475,14 @@ will contain placeholders of the form ``__Set______`` (where
manually by replacing all those 40 symbols by the hex
encoding of the address of the library contract.
+.. note::
+ Manually linking libraries on the generated bytecode is discouraged, because
+ it is restricted to 36 characters.
+ You should ask the compiler to link the libraries at the time
+ a contract is compiled by either using
+ the ``--libraries`` option of ``solc`` or the ``libraries`` key if you use
+ the standard-JSON interface to the compiler.
+
Restrictions for libraries in comparison to contracts:
- No state variables
@@ -1424,6 +1491,8 @@ Restrictions for libraries in comparison to contracts:
(These might be lifted at a later point.)
+.. _call-protection:
+
Call Protection For Libraries
=============================
@@ -1481,7 +1550,7 @@ available without having to add further code.
Let us rewrite the set example from the
:ref:`libraries` in this way::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
// This is the same code as before, just without comments
library Set {
@@ -1531,7 +1600,7 @@ Let us rewrite the set example from the
It is also possible to extend elementary types in that way::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
library Search {
function indexOf(uint[] storage self, uint value)
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 8a83ca55..361570a0 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -19,6 +19,8 @@ In particular, we need help in the following areas:
`up-for-grabs <https://github.com/ethereum/solidity/issues?q=is%3Aopen+is%3Aissue+label%3Aup-for-grabs>`_ which are
meant as introductory issues for external contributors.
+Please note that this project is released with a `Contributor Code of Conduct <https://raw.githubusercontent.com/ethereum/solidity/develop/CODE_OF_CONDUCT.md>`_. By participating in this project - in the issues, pull requests, or Gitter channels - you agree to abide by its terms.
+
How to Report Issues
====================
@@ -45,13 +47,14 @@ in addition to *what* you did (unless it is a tiny change).
If you need to pull in any changes from ``develop`` after making your fork (for
example, to resolve potential merge conflicts), please avoid using ``git merge``
-and instead, ``git rebase`` your branch.
+and instead, ``git rebase`` your branch. This will help us review your change
+more easily.
-Additionally, if you are writing a new feature, please ensure you write appropriate
-Boost test cases and place them under ``test/``.
+Additionally, if you are writing a new feature, please ensure you add appropriate
+test cases under ``test/`` (see below).
However, if you are making a larger change, please consult with the `Solidity Development Gitter channel
-<https://gitter.im/ethereum/solidity-dev>`_ (different from the one mentioned above, this on is
+<https://gitter.im/ethereum/solidity-dev>`_ (different from the one mentioned above, this one is
focused on compiler and language development instead of language use) first.
New features and bugfixes should be added to the ``Changelog.md`` file: please
@@ -62,50 +65,52 @@ Finally, please make sure you respect the `coding style
for this project. Also, even though we do CI testing, please test your code and
ensure that it builds locally before submitting a pull request.
-Please note that this project is released with a `Contributor Code of Conduct
-<https://raw.githubusercontent.com/ethereum/solidity/develop/CODE_OF_CONDUCT.md>`_.
-By participating in this project you agree to abide by its terms.
-
Thank you for your help!
Running the compiler tests
==========================
-Solidity includes different types of tests. They are included in the application
-called ``soltest``. Some of them require the ``cpp-ethereum`` client in testing mode,
+There is a script at ``scripts/tests.sh`` which executes most of the tests and
+runs ``aleth`` automatically if it is in the path, but does not download it,
+so it most likely will not work right away. Please read on for the details.
+
+Solidity includes different types of tests. Most of them are bundled in the application
+called ``soltest``. Some of them require the ``aleth`` client in testing mode,
some others require ``libz3`` to be installed.
-``soltest`` reads test contracts that are annotated with expected results
-stored in ``./test/libsolidity/syntaxTests``. In order for soltest to find these
-tests the root test directory has to be specified using the ``--testpath`` command
-line option, e.g. ``./build/test/soltest -- --testpath ./test``.
+To run a basic set of tests that neither require ``aleth`` nor ``libz3``, run
+``./scripts/soltest.sh --no-ipc --no-smt``. This script will run ``build/test/soltest``
+internally.
-To disable the z3 tests, use ``./build/test/soltest -- --no-smt --testpath ./test`` and
-to run a subset of the tests that do not require ``cpp-ethereum``, use
-``./build/test/soltest -- --no-ipc --testpath ./test``.
+The option ``--no-smt`` disables the tests that require ``libz3`` and
+``--no-ipc`` disables those that require ``aleth``.
-For all other tests, you need to install `cpp-ethereum <https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/eth>`_ and run it in testing mode: ``eth --test -d /tmp/testeth``.
+If you want to run the ipc tests (those test the semantics of the generated code),
+you need to install `aleth <https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/aleth_2018-06-20_artful>`_ and run it in testing mode: ``aleth --test -d /tmp/testeth`` (make sure to rename it).
-Then you run the actual tests: ``./build/test/soltest -- --ipcpath /tmp/testeth/geth.ipc --testpath ./test``.
+Then you run the actual tests: ``./scripts/soltest.sh --ipcpath /tmp/testeth/geth.ipc``.
To run a subset of tests, filters can be used:
-``soltest -t TestSuite/TestName -- --ipcpath /tmp/testeth/geth.ipc --testpath ./test``,
+``./scripts/soltest.sh -t TestSuite/TestName --ipcpath /tmp/testeth/geth.ipc``,
where ``TestName`` can be a wildcard ``*``.
-Alternatively, there is a testing script at ``scripts/test.sh`` which executes all tests and runs
-``cpp-ethereum`` automatically if it is in the path (but does not download it).
+The script ``scripts/tests.sh`` also runs commandline tests and compilation tests
+in addition to those found in ``soltest``.
-Travis CI even runs some additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target.
+The CI even runs some additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target.
.. note ::
- While any version of ``cpp-ethereum`` should be usable, this cannot be guaranteed, and it is suggested to use the same version that is used by the Solidity continuous integration tests.
- Currently the CI uses ``d661ac4fec0aeffbedcdc195f67f5ded0c798278`` of ``cpp-ethereum``.
+ Some versions of ``aleth`` cannot be used for testing. We suggest using the same version that is used by the Solidity continuous integration tests.
+ Currently the CI uses ``d661ac4fec0aeffbedcdc195f67f5ded0c798278`` of ``aleth``.
Writing and running syntax tests
--------------------------------
-As mentioned above, syntax tests are stored in individual contracts. These files must contain annotations, stating the expected result(s) of the respective test.
+Syntax tests check that the compiler generates the correct error messages for invalid code
+and properly accepts valid code.
+They are stored in individual files inside ``tests/libsolidity/syntaxTests``.
+These files must contain annotations, stating the expected result(s) of the respective test.
The test suite will compile and check them against the given expectations.
Example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol``
@@ -117,10 +122,12 @@ Example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol``
uint128 variable;
}
// ----
- // DeclarationError: Identifier already declared.
+ // DeclarationError: (36-52): Identifier already declared.
-A syntax test must contain at least the contract under test itself, followed by the separator ``----``. The additional comments above are used to describe the
-expected compiler errors or warnings. This section can be empty in case that the contract should compile without any errors or warnings.
+A syntax test must contain at least the contract under test itself, followed by the separator ``// ----``. The following comments are used to describe the
+expected compiler errors or warnings. The number range denotes the location in the source where the error occurred.
+In case the contract should compile without any errors or warning, the section after the separator has to be empty
+and the separator can be left out completely.
In the above example, the state variable ``variable`` was declared twice, which is not allowed. This will result in a ``DeclarationError`` stating that the identifier was already declared.
@@ -133,7 +140,7 @@ editing of failing contracts using your preferred text editor. Let's try to brea
uint256 variable;
}
// ----
- // DeclarationError: Identifier already declared.
+ // DeclarationError: (36-52): Identifier already declared.
Running ``./test/isoltest`` again will result in a test failure:
@@ -146,16 +153,16 @@ Running ``./test/isoltest`` again will result in a test failure:
}
Expected result:
- DeclarationError: Identifier already declared.
+ DeclarationError: (36-52): Identifier already declared.
Obtained result:
Success
-which prints the expected result next to the obtained result, but also provides a way to change edit / update / skip the current contract or to even quit.
-``isoltest`` offers several options for failing tests:
+``isoltest`` prints the expected result next to the obtained result, but also provides a way to change edit / update / skip the current contract or to even quit.
+It offers several options for failing tests:
-- edit: ``isoltest`` will try to open the editor that was specified before using ``isoltest --editor /path/to/editor``. If no path was set, this will result in a runtime error. In case an editor was specified, this will open it such that the contract can be adjusted.
-- update: Updates the contract under test. This will either remove the annotation which contains the exception not met or will add missing expectations. The test will then be run again.
+- edit: ``isoltest`` tries to open the contract in an editor so you can adjust it. It either uses the editor given on the command line (as ``isoltest --editor /path/to/editor``), in the environment variable ``EDITOR`` or just ``/usr/bin/editor`` (in this order).
+- update: Updates the contract under test. This either removes the annotation which contains the exception not met or adds missing expectations. The test will then be run again.
- skip: Skips the execution of this particular test.
- quit: Quits ``isoltest``.
@@ -178,8 +185,9 @@ and re-run the test. It will now pass again:
.. note::
- Please choose a name for the contract file, that is self-explainatory in the sense of what is been tested, e.g. ``double_variable_declaration.sol``.
- Do not put more than one contract into a single file. ``isoltest`` is currently not able to recognize them individually.
+ Please choose a name for the contract file that explains what it tests, e.g. ``double_variable_declaration.sol``.
+ Do not put more than one contract into a single file, unless you are testing inheritance or cross-contract calls.
+ Each file should test one aspect of your new feature.
Running the Fuzzer via AFL
@@ -278,7 +286,7 @@ use the tool ``scripts/uniqueErrors.sh`` to filter out the unique errors.
Whiskers
========
-*Whiskers* is a templating system similar to `Mustache <https://mustache.github.io>`_. It is used by the
+*Whiskers* is a string templating system similar to `Mustache <https://mustache.github.io>`_. It is used by the
compiler in various places to aid readability, and thus maintainability and verifiability, of the code.
The syntax comes with a substantial difference to Mustache: the template markers ``{{`` and ``}}`` are
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 5810aaa7..80311a63 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -14,13 +14,13 @@ parameters as output.
Input Parameters
----------------
-The input parameters are declared the same way as variables are. As an
-exception, unused parameters can omit the variable name.
+The input parameters are declared the same way as variables are.
+The name of unused parameters can be omitted.
For example, suppose we want our contract to
accept one kind of external calls with two integers, we would write
something like::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract Simple {
uint sum;
@@ -29,6 +29,9 @@ something like::
}
}
+Input parameters can be used just as any other local variable
+can be used, they can also be assigned to.
+
Output Parameters
-----------------
@@ -37,7 +40,7 @@ The output parameters can be declared with the same syntax after the
the sum and the product of the two given integers, then we would
write::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract Simple {
function arithmetic(uint _a, uint _b)
@@ -51,24 +54,20 @@ write::
}
The names of output parameters can be omitted.
-The output values can also be specified using ``return`` statements.
-The ``return`` statements are also capable of returning multiple
-values, see :ref:`multi-return`.
-Return parameters are initialized to zero; if they are not explicitly
-set, they stay to be zero.
-
-Input parameters and output parameters can be used as expressions in
-the function body. There, they are also usable in the left-hand side
-of assignment.
+The output values can also be specified using ``return`` statements,
+which are also capable of :ref:`returning multiple values<multi-return>`.
+Return parameters can be used as any other local variable and they
+are zero-initialized; if they are not explicitly
+set, they stay zero.
.. index:: if, else, while, do/while, for, break, continue, return, switch, goto
Control Structures
===================
-Most of the control structures from JavaScript are available in Solidity
-except for ``switch`` and ``goto``. So
-there is: ``if``, ``else``, ``while``, ``do``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with
+Most of the control structures known from curly-braces languages are available in Solidity:
+
+There is: ``if``, ``else``, ``while``, ``do``, ``for``, ``break``, ``continue``, ``return``, with
the usual semantics known from C or JavaScript.
Parentheses can *not* be omitted for conditionals, but curly brances can be omitted
@@ -100,7 +99,7 @@ Internal Function Calls
Functions of the current contract can be called directly ("internally"), also recursively, as seen in
this nonsensical example::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function g(uint a) public pure returns (uint ret) { return a + f(); }
@@ -112,6 +111,9 @@ the effect that the current memory is not cleared, i.e. passing memory reference
to internally-called functions is very efficient. Only functions of the same
contract can be called internally.
+You should still avoid excessive recursion, as every internal function call
+uses up at least one stack slot and there are at most 1024 slots available.
+
External Function Calls
-----------------------
@@ -127,7 +129,7 @@ all function arguments have to be copied to memory.
When calling functions of other contracts, the amount of Wei sent with the call and
the gas can be specified with special options ``.value()`` and ``.gas()``, respectively::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract InfoFeed {
function info() public payable returns (uint ret) { return 42; }
@@ -143,7 +145,7 @@ You need to use the modifier ``payable`` with the ``info`` function because
otherwise, the ``.value()`` option would not be available.
.. warning::
- Be careful that ``feed.info.value(10).gas(800)`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the parentheses at the end perform the actual call.
+ Be careful that ``feed.info.value(10).gas(800)`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the parentheses at the end perform the actual call. So in this case, the function is not called.
Function calls cause exceptions if the called contract does not exist (in the
sense that the account does not contain code) or if the called contract itself
@@ -167,14 +169,14 @@ throws an exception or goes out of gas.
Named Calls and Anonymous Function Parameters
---------------------------------------------
-Function call arguments can also be given by name, in any order,
+Function call arguments can be given by name, in any order,
if they are enclosed in ``{ }`` as can be seen in the following
example. The argument list has to coincide by name with the list of
parameters from the function declaration, but can be in arbitrary order.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
mapping(uint => uint) data;
@@ -197,7 +199,7 @@ Those parameters will still be present on the stack, but they are inaccessible.
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
// omitted name for parameter
@@ -214,13 +216,13 @@ Those parameters will still be present on the stack, but they are inaccessible.
Creating Contracts via ``new``
==============================
-A contract can create a new contract using the ``new`` keyword. The full
-code of the contract being created has to be known in advance, so recursive
-creation-dependencies are not possible.
+A contract can create other contracts using the ``new`` keyword. The full
+code of the contract being created has to be known when the creating contract
+is compiled so recursive creation-dependencies are not possible.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract D {
uint public x;
@@ -244,7 +246,7 @@ creation-dependencies are not possible.
}
}
-As seen in the example, it is possible to forward Ether while creating
+As seen in the example, it is possible to send Ether while creating
an instance of ``D`` using the ``.value()`` option, but it is not possible
to limit the amount of gas.
If the creation fails (due to out-of-stack, not enough balance or other problems),
@@ -269,8 +271,11 @@ Assignment
Destructuring Assignments and Returning Multiple Values
-------------------------------------------------------
-Solidity internally allows tuple types, i.e. a list of objects of potentially different types whose size is a constant at compile-time. Those tuples can be used to return multiple values at the same time.
-These can then either be assigned to newly declared variables or to pre-existing variables (or LValues in general):
+Solidity internally allows tuple types, i.e. a list of objects of potentially different types whose number is a constant at compile-time. Those tuples can be used to return multiple values at the same time.
+These can then either be assigned to newly declared variables or to pre-existing variables (or LValues in general).
+
+Tuples are not proper types in Solidity, they can only be used to form syntactic
+groupings of expressions.
::
@@ -294,15 +299,23 @@ These can then either be assigned to newly declared variables or to pre-existing
}
}
+It is not possible to mix variable declarations and non-declaration assignments,
+i.e. the following is not valid: ``(x, uint y) = (1, 2);``
+
.. note::
Prior to version 0.5.0 it was possible to assign to tuples of smaller size, either
filling up on the left or on the right side (which ever was empty). This is
now disallowed, so both sides have to have the same number of components.
+.. warning::
+ Be careful when assigning to multiple variables at the same time when
+ reference types are involved, because it could lead to unexpected
+ copying behaviour.
+
Complications for Arrays and Structs
------------------------------------
-The semantics of assignment are a bit more complicated for non-value types like arrays and structs.
+The semantics of assignments are a bit more complicated for non-value types like arrays and structs.
Assigning *to* a state variable always creates an independent copy. On the other hand, assigning to a local variable creates an independent copy only for elementary types, i.e. static types that fit into 32 bytes. If structs or arrays (including ``bytes`` and ``string``) are assigned from a state variable to a local variable, the local variable holds a reference to the original state variable. A second assignment to the local variable does not modify the state but only changes the reference. Assignments to members (or elements) of the local variable *do* change the state.
.. index:: ! scoping, declarations, default value
@@ -320,11 +333,11 @@ and ``string``, the default value is an empty array or string.
Scoping in Solidity follows the widespread scoping rules of C99
(and many other languages): Variables are visible from the point right after their declaration
-until the end of a ``{ }``-block. As an exception to this rule, variables declared in the
+until the end of the smallest ``{ }``-block that contains the declaration. As an exception to this rule, variables declared in the
initialization part of a for-loop are only visible until the end of the for-loop.
Variables and other items declared outside of a code block, for example functions, contracts,
-user-defined types, etc., do not change their scoping behaviour. This means you can
+user-defined types, etc., are visible even before they were declared. This means you can
use state variables before they are declared and call functions recursively.
As a consequence, the following examples will compile without warnings, since
@@ -332,7 +345,7 @@ the two variables have the same name but disjoint scopes.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract C {
function minimalScoping() pure public {
{
@@ -353,7 +366,7 @@ In any case, you will get a warning about the outer variable being shadowed.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
// This will report a warning
contract C {
function f() pure public returns (uint) {
@@ -368,12 +381,12 @@ In any case, you will get a warning about the outer variable being shadowed.
.. warning::
Before version 0.5.0 Solidity followed the same scoping rules as JavaScript, that is, a variable declared anywhere within a function would be in scope
- for the entire function, regardless where it was declared. Note that this is a breaking change. The following example shows a code snippet that used
+ for the entire function, regardless where it was declared. The following example shows a code snippet that used
to compile but leads to an error starting from version 0.5.0.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
// This will not compile
contract C {
function f() pure public returns (uint) {
@@ -385,6 +398,8 @@ In any case, you will get a warning about the outer variable being shadowed.
.. index:: ! exception, ! throw, ! assert, ! require, ! revert
+.. _assert-and-require:
+
Error handling: Assert, Require, Revert and Exceptions
======================================================
@@ -398,17 +413,17 @@ If used properly, analysis tools can evaluate your contract to identify the cond
There are two other ways to trigger exceptions: The ``revert`` function can be used to flag an error and
revert the current call. It is possible to provide a string message containing details about the error
that will be passed back to the caller.
-The deprecated keyword ``throw`` can also be used as an alternative to ``revert()`` (but only without error message).
.. note::
- From version 0.4.13 the ``throw`` keyword is deprecated and will be phased out in the future.
+ There used to be a keyword called ``throw`` with the same semantics as ``revert()`` which
+ whas deprecated in version 0.4.13 and removed in version 0.5.0.
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``, ``callcode`` and ``staticcall`` -- those return ``false`` in case
+and the low-level functions ``call``, ``delegatecall`` and ``staticcall`` -- those return ``false`` as their first return value in case
of an exception instead of "bubbling up".
.. warning::
- 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.
+ The low-level functions ``call``, ``delegatecall`` and ``staticcall`` return ``true`` as their first return value 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.
@@ -418,10 +433,10 @@ a message string for ``require``, but not for ``assert``.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract Sharer {
- function sendHalf(address addr) public payable returns (uint balance) {
+ function sendHalf(address payable addr) public payable returns (uint balance) {
require(msg.value % 2 == 0, "Even value required.");
uint balanceBeforeTransfer = address(this).balance;
addr.transfer(msg.value / 2);
@@ -445,7 +460,6 @@ An ``assert``-style exception is generated in the following situations:
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``, ``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").
@@ -465,7 +479,7 @@ The following example shows how an error string can be used together with revert
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract VendingMachine {
function buy(uint amount) public payable {
diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst
index d2b7de9c..a474f905 100644
--- a/docs/frequently-asked-questions.rst
+++ b/docs/frequently-asked-questions.rst
@@ -43,21 +43,15 @@ Can you return an array or a ``string`` from a solidity function call?
Yes. See `array_receiver_and_returner.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/60_array_receiver_and_returner.sol>`_.
-What is problematic, though, is returning any variably-sized data (e.g. a
-variably-sized array like ``uint[]``) from a function **called from within Solidity**.
-This is a limitation of the EVM and will be solved with the next protocol update.
-
-Returning variably-sized data as part of an external transaction or call is fine.
-
Is it possible to in-line initialize an array like so: ``string[] myarray = ["a", "b"];``
=========================================================================================
Yes. However it should be noted that this currently only works with statically sized memory arrays. You can even create an inline memory
-array in the return statement. Pretty cool, huh?
+array in the return statement.
Example::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function f() public pure returns (uint8[5] memory) {
@@ -70,7 +64,7 @@ Example::
Can a contract function return a ``struct``?
============================================
-Yes, but only in ``internal`` function calls.
+Yes, but only in ``internal`` function calls or if ``pragma experimental "ABIEncoderV2";`` is used.
If I return an ``enum``, I only get integer values in web3.js. How to get the named values?
===========================================================================================
@@ -87,7 +81,7 @@ should be noted that you must declare them as static memory arrays.
Examples::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
struct S {
@@ -127,7 +121,7 @@ which will be extended in the future. In addition, Arachnid has written `solidit
For now, if you want to modify a string (even when you only want to know its length),
you should always convert it to a ``bytes`` first::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
string s;
@@ -145,7 +139,17 @@ you should always convert it to a ``bytes`` first::
Can I concatenate two strings?
==============================
-You have to do it manually for now.
+Yes, you can use ``abi.encodePacked``::
+
+ pragma solidity >=0.4.0 <0.6.0;
+
+ library ConcatHelper {
+ function concat(bytes memory a, bytes memory b)
+ internal pure returns (bytes memory) {
+ return abi.encodePacked(a, b);
+ }
+ }
+
Why is the low-level function ``.call()`` less favorable than instantiating a contract with a variable (``ContractB b;``) and executing its functions (``b.doSomething();``)?
=============================================================================================================================================================================
@@ -282,7 +286,7 @@ In the case of a ``contract A`` calling a new instance of ``contract B``, parent
You will need to make sure that you have both contracts aware of each other's presence and that ``contract B`` has a ``payable`` constructor.
In this example::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract B {
constructor() public payable {}
@@ -299,8 +303,8 @@ In this example::
Can a contract function accept a two-dimensional array?
=======================================================
-This is not yet implemented for external calls and dynamic arrays -
-you can only use one level of dynamic arrays.
+If you want to pass two-dimensional arrays across non-internal functions,
+you most likely need to use ``pragma experimental "ABIEncoderV2";``.
What is the relationship between ``bytes32`` and ``string``? Why is it that ``bytes32 somevar = "stringliteral";`` works and what does the saved 32-byte hex value mean?
========================================================================================================================================================================
@@ -330,7 +334,7 @@ Can a contract pass an array (static size) or string or ``bytes`` (dynamic size)
Sure. Take care that if you cross the memory / storage boundary,
independent copies will be created::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
uint[20] x;
@@ -367,7 +371,7 @@ contract level) with ``arrayname.length = <some new length>;``. If you get the
::
- pragma solidity ^0.4.18;
+ pragma solidity >=0.4.18 <0.6.0;
// This will not compile
contract C {
@@ -401,7 +405,7 @@ case in C or Java).
Is it possible to return an array of strings (``string[]``) from a Solidity function?
=====================================================================================
-Not yet, as this requires two levels of dynamic arrays (``string`` is a dynamic array itself).
+Only when ``pragma experimental "ABIEncoderV2";`` is used.
What does the following strange check do in the Custom Token contract?
======================================================================
diff --git a/docs/grammar.txt b/docs/grammar.txt
index 43ef07a9..b9c8ddb9 100644
--- a/docs/grammar.txt
+++ b/docs/grammar.txt
@@ -50,6 +50,7 @@ TypeName = ElementaryTypeName
| Mapping
| ArrayTypeName
| FunctionTypeName
+ | ( 'address' 'payable' )
UserDefinedTypeName = Identifier ( '.' Identifier )*
@@ -131,7 +132,7 @@ HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')
StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"'
Identifier = [a-zA-Z_$] [a-zA-Z_$0-9]*
-HexNumber = '0' [xX] [0-9a-fA-F]+
+HexNumber = '0x' [0-9a-fA-F]+
DecimalNumber = [0-9]+ ( '.' [0-9]* )? ( [eE] [0-9]+ )?
TupleExpression = '(' ( Expression? ( ',' Expression? )* )? ')'
diff --git a/docs/index.rst b/docs/index.rst
index 20fa1505..0449ff42 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -6,15 +6,18 @@ Solidity
:alt: Solidity logo
:align: center
-Solidity is a contract-oriented, high-level language for implementing smart contracts.
-It was influenced by C++, Python and JavaScript
-and is designed to target the Ethereum Virtual Machine (EVM).
+Solidity is an object-oriented, high-level language for implementing smart
+contracts. Smart contracts are programs which govern the behaviour of accounts
+within the Ethereum state.
+
+Solidity was influenced by C++, Python and JavaScript and is designed to target
+the Ethereum Virtual Machine (EVM).
Solidity is statically typed, supports inheritance, libraries and complex
user-defined types among other features.
-As you will see, it is possible to create contracts for voting,
-crowdfunding, blind auctions, multi-signature wallets and more.
+With Solidity you can create contracts for uses such as voting, crowdfunding, blind auctions,
+and multi-signature wallets.
.. note::
The best way to try out Solidity right now is using
diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst
index 34806f4a..9d4be70d 100644
--- a/docs/installing-solidity.rst
+++ b/docs/installing-solidity.rst
@@ -35,13 +35,15 @@ 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 the ways to access the compiler described
+further down this page. The
: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>`_.
+the full-featured compiler, `solc`. The usage of `solcjs` is documented inside its own
+`repository <https://github.com/ethereum/solc-js>`_.
Note: The solc-js project is derived from the C++
-`solc` by using Emscripten. `solc-js` can be used in JavaScript projects directly (such as Remix).
+`solc` by using Emscripten which means that both use the same compiler source code.
+`solc-js` can be used in JavaScript projects directly (such as Remix).
Please refer to the solc-js repository for instructions.
.. code-block:: bash
@@ -50,7 +52,7 @@ Please refer to the solc-js repository for instructions.
.. note::
- The commandline is named `solcjs`.
+ The commandline executable is named `solcjs`.
The comandline options of `solcjs` are not compatible with `solc` and tools (such as `geth`)
expecting the behaviour of `solc` will not work with `solcjs`.
@@ -76,7 +78,8 @@ Binary Packages
Binary packages of Solidity are available at
`solidity/releases <https://github.com/ethereum/solidity/releases>`_.
-We also have PPAs for Ubuntu. For the latest stable version.
+We also have PPAs for Ubuntu, you can get the latest stable
+version using the following commands:
.. code-block:: bash
@@ -84,7 +87,7 @@ We also have PPAs for Ubuntu. For the latest stable version.
sudo apt-get update
sudo apt-get install solc
-If you want to use the cutting edge developer version:
+The nightly version can be installed using these commands:
.. code-block:: bash
@@ -99,7 +102,8 @@ We are also releasing a `snap package <https://snapcraft.io/>`_, which is instal
sudo snap install solc
-Or if you want to help testing the unstable solc with the most recent changes from the development branch:
+If you want to help testing the latest development version of Solidity
+with the most recent changes, please use the following:
.. code-block:: bash
@@ -111,10 +115,9 @@ Arch Linux also has packages, albeit limited to the latest development version:
pacman -S solidity
-Homebrew is missing pre-built bottles at the time of writing,
-following a Jenkins to TravisCI migration, but Homebrew
-should still work just fine as a means to build-from-source.
-We will re-add the pre-built bottles soon.
+We distribute the Solidity compiler through Homebrow
+as a build-from-source version. Pre-built bottles are
+currently not supported.
.. code-block:: bash
@@ -151,29 +154,18 @@ Gentoo Linux also provides a solidity package that can be installed using ``emer
Building from Source
====================
-Clone the Repository
---------------------
-
-To clone the source code, execute the following command:
-
-.. code-block:: bash
-
- git clone --recursive https://github.com/ethereum/solidity.git
- cd solidity
-
-If you want to help developing Solidity,
-you should fork Solidity and add your personal fork as a second remote:
-
-.. code-block:: bash
-
- cd solidity
- git remote add personal git@github.com:[username]/solidity.git
+Prerequisites - Linux
+---------------------
-Solidity has git submodules. Ensure they are properly loaded:
+You need to install the following dependencies for Linux builds of Solidity:
-.. code-block:: bash
++-----------------------------------+-------------------------------------------------------+
+| Software | Notes |
++===================================+=======================================================+
+| `Git for Linux`_ | Command-line tool for retrieving source from Github. |
++-----------------------------------+-------------------------------------------------------+
- git submodule update --init --recursive
+.. _Git for Linux: https://git-scm.com/download/linux
Prerequisites - macOS
---------------------
@@ -201,7 +193,7 @@ if you ever want to start again from scratch.
Prerequisites - Windows
-----------------------
-You will need to install the following dependencies for Windows builds of Solidity:
+You need to install the following dependencies for Windows builds of Solidity:
+-----------------------------------+-------------------------------------------------------+
| Software | Notes |
@@ -236,13 +228,34 @@ in Visual Studio 2017 Build Tools or Visual Studio 2017:
.. _Visual Studio 2017: https://www.visualstudio.com/vs/
.. _Visual Studio 2017 Build Tools: https://www.visualstudio.com/downloads/#build-tools-for-visual-studio-2017
+Clone the Repository
+--------------------
+
+To clone the source code, execute the following command:
+
+.. code-block:: bash
+
+ git clone --recursive https://github.com/ethereum/solidity.git
+ cd solidity
+
+If you want to help developing Solidity,
+you should fork Solidity and add your personal fork as a second remote:
+
+.. code-block:: bash
+
+ git remote add personal git@github.com:[username]/solidity.git
+
+Solidity has git submodules. Ensure they are properly loaded:
+
+.. code-block:: bash
+
+ git submodule update --init --recursive
External Dependencies
---------------------
-We now have a "one button" script which installs all required external dependencies
-on macOS, Windows and on numerous Linux distros. This used to be a multi-step
-manual process, but is now a one-liner:
+We have a helper script which installs all required external dependencies
+on macOS, Windows and on numerous Linux distros.
.. code-block:: bash
@@ -261,6 +274,8 @@ Command-Line Build
**Be sure to install External Dependencies (see above) before build.**
Solidity project uses CMake to configure the build.
+You might want to install ccache to speed up repeated builds.
+CMake will pick it up automatically.
Building Solidity is quite similar on Linux, macOS and other Unices:
.. code-block:: bash
@@ -276,7 +291,7 @@ or even easier:
#note: this will install binaries solc and soltest at usr/local/bin
./scripts/build.sh
-And even for Windows:
+And for Windows:
.. code-block:: bash
@@ -300,6 +315,8 @@ CMake options
If you are interested what CMake options are available run ``cmake .. -LH``.
+.. _smt_solvers_build:
+
SMT Solvers
-----------
Solidity can be built against SMT solvers and will do so by default if
@@ -329,7 +346,7 @@ The Solidity version string contains four parts:
- the version number
- pre-release tag, usually set to ``develop.YYYY.MM.DD`` or ``nightly.YYYY.MM.DD``
- commit in the format of ``commit.GITHASH``
-- platform has arbitrary number of items, containing details about the platform and compiler
+- platform, which has an arbitrary number of items, containing details about the platform and compiler
If there are local modifications, the commit will be postfixed with ``.mod``.
diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst
index 7bfee0a1..f5d5f89e 100644
--- a/docs/introduction-to-smart-contracts.rst
+++ b/docs/introduction-to-smart-contracts.rst
@@ -8,15 +8,16 @@ Introduction to Smart Contracts
A Simple Smart Contract
***********************
-Let us begin with the most basic example. It is fine if you do not understand everything
-right now, we will go into more detail later.
+Let us begin with a basic example that sets the value of a variable and exposes
+it for other contracts to access. It is fine if you do not understand
+everything right now, we will go into more detail later.
Storage
=======
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract SimpleStorage {
uint storedData;
@@ -32,9 +33,9 @@ Storage
The first line simply tells that the source code is written for
Solidity version 0.4.0 or anything newer that does not break functionality
-(up to, but not including, version 0.5.0). This is to ensure that the
+(up to, but not including, version 0.6.0). This is to ensure that the
contract is not compilable with a new (breaking) compiler version, where it could behave differently.
-So-called pragmas are common instrutions for compilers about how to treat the
+So-called pragmas are common instructions for compilers about how to treat the
source code (e.g. `pragma once <https://en.wikipedia.org/wiki/Pragma_once>`_).
A contract in the sense of Solidity is a collection of code (its *functions*) and
@@ -80,7 +81,7 @@ registering with username and password — all you need is an Ethereum keypair.
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
contract Coin {
// The keyword "public" makes those variables
@@ -183,23 +184,34 @@ the user interface.
.. index:: coin
-The special function ``Coin`` is the
-constructor which is run during creation of the contract and
+The constructor is a special function which is run during creation of the contract and
cannot be called afterwards. It permanently stores the address of the person creating the
-contract: ``msg`` (together with ``tx`` and ``block``) is a magic global variable that
+contract: ``msg`` (together with ``tx`` and ``block``) is a special global variable that
contains some properties which allow access to the blockchain. ``msg.sender`` is
always the address where the current (external) function call came from.
Finally, the functions that will actually end up with the contract and can be called
by users and contracts alike are ``mint`` and ``send``.
If ``mint`` is called by anyone except the account that created the contract,
-nothing will happen. On the other hand, ``send`` can be used by anyone (who already
-has some of these coins) to send coins to anyone else. Note that if you use
-this contract to send coins to an address, you will not see anything when you
-look at that address on a blockchain explorer, because the fact that you sent
-coins and the changed balances are only stored in the data storage of this
-particular coin contract. By the use of events it is relatively easy to create
-a "blockchain explorer" that tracks transactions and balances of your new coin.
+nothing will happen. This is ensured by the special function ``require`` which
+causes all changes to be reverted if its argument evaluates to false.
+The second call to ``require`` ensures that there will not be too many coins,
+which could cause overflow errors later.
+
+On the other hand, ``send`` can be used by anyone (who already
+has some of these coins) to send coins to anyone else. If you do not have
+enough coins to send, the ``require`` call will fail and also provide the
+user with an appropriate error message string.
+
+.. note::
+ If you use
+ this contract to send coins to an address, you will not see anything when you
+ look at that address on a blockchain explorer, because the fact that you sent
+ coins and the changed balances are only stored in the data storage of this
+ particular coin contract. By the use of events it is relatively easy to create
+ a "blockchain explorer" that tracks transactions and balances of your new coin,
+ but you have to inspect the coin contract address and not the addresses of the
+ coin owners.
.. _blockchain-basics:
@@ -209,7 +221,7 @@ Blockchain Basics
Blockchains as a concept are not too hard to understand for programmers. The reason is that
most of the complications (mining, `hashing <https://en.wikipedia.org/wiki/Cryptographic_hash_function>`_, `elliptic-curve cryptography <https://en.wikipedia.org/wiki/Elliptic_curve_cryptography>`_, `peer-to-peer networks <https://en.wikipedia.org/wiki/Peer-to-peer>`_, etc.)
-are just there to provide a certain set of features and promises. Once you accept these
+are just there to provide a certain set of features and promises for the platform. Once you accept these
features as given, you do not have to worry about the underlying technology - or do you have
to know how Amazon's AWS works internally in order to use it?
@@ -224,7 +236,7 @@ If you want to change something in the database, you have to create a so-called
which has to be accepted by all others.
The word transaction implies that the change you want to make (assume you want to change
two values at the same time) is either not done at all or completely applied. Furthermore,
-while your transaction is applied to the database, no other transaction can alter it.
+while your transaction is being applied to the database, no other transaction can alter it.
As an example, imagine a table that lists the balances of all accounts in an
electronic currency. If a transfer from one account to another is requested,
@@ -243,12 +255,13 @@ only the person holding the keys to the account can transfer money from it.
Blocks
======
-One major obstacle to overcome is what, in Bitcoin terms, is called a "double-spend attack":
-What happens if two transactions exist in the network that both want to empty an account,
-a so-called conflict?
+One major obstacle to overcome is what (in Bitcoin terms) is called a "double-spend attack":
+What happens if two transactions exist in the network that both want to empty an account?
+Only one of the transactions can be valid, typically the one that is accepted first.
+The problem is that "first" is not an objective term in a peer-to-peer network.
-The abstract answer to this is that you do not have to care. An order of the transactions
-will be selected for you, the transactions will be bundled into what is called a "block"
+The abstract answer to this is that you do not have to care. A globally accepted order of the transactions
+will be selected for you, solving the conflict. The transactions will be bundled into what is called a "block"
and then they will be executed and distributed among all participating nodes.
If two transactions contradict each other, the one that ends up being second will
be rejected and not become part of the block.
@@ -259,14 +272,16 @@ Ethereum this is roughly every 17 seconds.
As part of the "order selection mechanism" (which is called "mining") it may happen that
blocks are reverted from time to time, but only at the "tip" of the chain. The more
-blocks that are added on top, the less likely it is. So it might be that your transactions
+blocks are added on top of a particular block, the less likely this block will be reverted. So it might be that your transactions
are reverted and even removed from the blockchain, but the longer you wait, the less
likely it will be.
.. note::
- Transactions are not guaranteed to happen on the next block or any future specific block, since it is up to the miners to include transactions and not the submitter of the transaction. This applies to function calls and contract creation transactions alike.
+ Transactions are not guaranteed to be included in the next block or any specific future block,
+ since it is not up to the submitter of a transaction, but up to the miners to determine in which block the transaction is included.
- If you want to schedule future calls of your contract, you can use the `alarm clock <http://www.ethereum-alarm-clock.com/>`_ service.
+ If you want to schedule future calls of your contract, you can use
+ the `alarm clock <http://www.ethereum-alarm-clock.com/>`_ or a similar oracle service.
.. _the-ethereum-virtual-machine:
@@ -308,7 +323,7 @@ Every account has a persistent key-value store mapping 256-bit words to 256-bit
words called **storage**.
Furthermore, every account has a **balance** in
-Ether (in "Wei" to be exact) which can be modified by sending transactions that
+Ether (in "Wei" to be exact, `1 ether` is `10**18 wei`) which can be modified by sending transactions that
include Ether.
.. index:: ! transaction
@@ -318,7 +333,7 @@ Transactions
A transaction is a message that is sent from one account to another
account (which might be the same or the special zero-account, see below).
-It can include binary data (its payload) and Ether.
+It can include binary data (which is called "payload") and Ether.
If the target account contains code, that code is executed and
the payload is provided as input data.
@@ -329,7 +344,7 @@ As already mentioned, the address of that contract is not
the zero address but an address derived from the sender and
its number of transactions sent (the "nonce"). The payload
of such a contract creation transaction is taken to be
-EVM bytecode and executed. The output of this execution is
+EVM bytecode and executed. The output data of this execution is
permanently stored as the code of the contract.
This means that in order to create a contract, you do not
send the actual code of the contract, but in fact code that
@@ -348,36 +363,38 @@ Gas
Upon creation, each transaction is charged with a certain amount of **gas**,
whose purpose is to limit the amount of work that is needed to execute
-the transaction and to pay for this execution. While the EVM executes the
+the transaction and to pay for this execution at the same time. While the EVM executes the
transaction, the gas is gradually depleted according to specific rules.
The **gas price** is a value set by the creator of the transaction, who
has to pay ``gas_price * gas`` up front from the sending account.
-If some gas is left after the execution, it is refunded in the same way.
+If some gas is left after the execution, it is refunded to the creator in the same way.
-If the gas is used up at any point (i.e. it is negative),
+If the gas is used up at any point (i.e. it would be negative),
an out-of-gas exception is triggered, which reverts all modifications
made to the state in the current call frame.
-Any unused gas is refunded at the end of the transaction.
-
.. index:: ! storage, ! memory, ! stack
Storage, Memory and the Stack
=============================
-The Ethereum Virtual Machine has three areas where it can store data.
+The Ethereum Virtual Machine has three areas where it can store data,
+storage, memory and the stack, which are explained in the following
+paragraphs.
-Each account has a data area called **storage**, which is persistent between function calls.
+Each account has a data area called **storage**, which is persistent between function calls
+and transactions.
Storage is a key-value store that maps 256-bit words to 256-bit words.
-It is not possible to enumerate storage from within a contract and it is comparatively costly to read, and even more to modify storage.
+It is not possible to enumerate storage from within a contract and it is
+comparatively costly to read, and even more to modify storage.
A contract can neither read nor write to any storage apart from its own.
The second data area is called **memory**, of which a contract obtains
a freshly cleared instance for each message call. Memory is linear and can be
addressed at byte level, but reads are limited to a width of 256 bits, while writes
can be either 8 bits or 256 bits wide. Memory is expanded by a word (256-bit), when
-accessing (either reading or writing) a previously untouched memory word (ie. any offset
+accessing (either reading or writing) a previously untouched memory word (i.e. any offset
within a word). At the time of expansion, the cost in gas must be paid. Memory is more
costly the larger it grows (it scales quadratically).
@@ -390,7 +407,8 @@ the topmost 16 elements to the top of the stack or swap the
topmost element with one of the 16 elements below it.
All other operations take the topmost two (or one, or more, depending on
the operation) elements from the stack and push the result onto the stack.
-Of course it is possible to move stack elements to storage or memory,
+Of course it is possible to move stack elements to storage or memory
+in order to get deeper access to the stack,
but it is not possible to just access arbitrary elements deeper in the stack
without first removing the top of the stack.
@@ -400,13 +418,17 @@ Instruction Set
===============
The instruction set of the EVM is kept minimal in order to avoid
-incorrect implementations which could cause consensus problems.
-All instructions operate on the basic data type, 256-bit words.
+incorrect or inconsistent implementations which could cause consensus problems.
+All instructions operate on the basic data type, 256-bit words or on slices of memory
+(or other byte arrays).
The usual arithmetic, bit, logical and comparison operations are present.
Conditional and unconditional jumps are possible. Furthermore,
contracts can access relevant properties of the current block
like its number and timestamp.
+For a complete list, please see the :ref:`list of opcodes <opcodes>` as part of the inline
+assembly documentation.
+
.. index:: ! message call, function;call
Message Calls
@@ -431,9 +453,12 @@ will receive a freshly cleared instance of memory and has access to the
call payload - which will be provided in a separate area called the **calldata**.
After it has finished execution, it can return data which will be stored at
a location in the caller's memory preallocated by the caller.
+All such calls are fully synchronous.
Calls are **limited** to a depth of 1024, which means that for more complex
-operations, loops should be preferred over recursive calls.
+operations, loops should be preferred over recursive calls. Furthermore,
+only 63/64th of the gas can be forwarded in a message call, which causes a
+depth limit of a little less than 1000 in practice.
.. index:: delegatecall, callcode, library
@@ -451,7 +476,7 @@ refer to the calling contract, only the code is taken from the called address.
This makes it possible to implement the "library" feature in Solidity:
Reusable library code that can be applied to a contract's storage, e.g. in
-order to implement a complex data structure.
+order to implement a complex data structure.
.. index:: log
@@ -460,13 +485,13 @@ Logs
It is possible to store data in a specially indexed data structure
that maps all the way up to the block level. This feature called **logs**
-is used by Solidity in order to implement **events**.
+is used by Solidity in order to implement :ref:`events <events>`.
Contracts cannot access log data after it has been created, but they
can be efficiently accessed from outside the blockchain.
Since some part of the log data is stored in `bloom filters <https://en.wikipedia.org/wiki/Bloom_filter>`_, it is
possible to search for this data in an efficient and cryptographically
secure way, so network peers that do not download the whole blockchain
-("light clients") can still find these logs.
+(so-called "light clients") can still find these logs.
.. index:: contract creation
@@ -474,7 +499,7 @@ Create
======
Contracts can even create other contracts using a special opcode (i.e.
-they do not simply call the zero address). The only difference between
+they do not simply call the zero address as a transaction would). The only difference between
these **create calls** and normal message calls is that the payload data is
executed and the result stored as code and the caller / creator
receives the address of the new contract on the stack.
diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst
index c1a1669a..fb18f8a9 100644
--- a/docs/layout-of-source-files.rst
+++ b/docs/layout-of-source-files.rst
@@ -2,15 +2,29 @@
Layout of a Solidity Source File
********************************
-Source files can contain an arbitrary number of contract definitions, include directives
-and pragma directives.
+Source files can contain an arbitrary number of
+:ref:`contract definitions<contract_structure>`, import_ directives
+and :ref:`pragma directives<pragma>`.
+
+.. index:: ! pragma
+
+.. _pragma:
+
+Pragmas
+=======
+
+The ``pragma`` keyword can be used to enable certain compiler features
+or checks. A pragma directive is always local to a source file, so
+you have to add the pragma to all your files if you want enable it
+in all of your project. If you :ref:`import<import>` another file, the pragma
+from that file will not automatically apply to the importing file.
.. index:: ! pragma, version
.. _version_pragma:
Version Pragma
-==============
+--------------
Source files can (and should) be annotated with a so-called version pragma to reject
being compiled with future compiler versions that might introduce incompatible
@@ -35,6 +49,53 @@ the exact version of the compiler, so that bugfix releases are still possible.
It is possible to specify much more complex rules for the compiler version,
the expression follows those used by `npm <https://docs.npmjs.com/misc/semver>`_.
+.. note::
+ Using the version pragma will *not* change the version of the compiler.
+ It will also *not* enable or disable features of the compiler. It will just
+ instruct the compiler to check whether its version matches the one
+ required by the pragma. If it does not match, the compiler will issue
+ an error.
+
+.. index:: ! pragma, experimental
+
+.. _experimental_pragma:
+
+Experimental Pragma
+-------------------
+
+The second pragma is the experimental pragma. It can be used to enable
+features of the compiler or language that are not yet enabled by default.
+The following experimental pragmas are currently supported:
+
+
+ABIEncoderV2
+~~~~~~~~~~~~
+
+The new ABI encoder is able to encode and decode arbitrarily nested
+arrays and structs. It produces less optimal code (the optimizer
+for this part of the code is still under development) and has not
+received as much testing as the old encoder. You can activate it
+using ``pragma experimental ABIEncoderV2;``.
+
+.. _smt_checker:
+
+SMTChecker
+~~~~~~~~~~
+
+This component has to be enabled when the Solidity compiler is built
+and therefore it is not available in all Solidity binaries.
+The :ref:`build instructions<smt_solvers_build>` explain how to activate this option.
+It is activated for the Ubuntu PPA releases in most versions,
+but not for solc-js, the Docker images, Windows binaries or the
+statically-built Linux binaries.
+
+If you use
+``pragma experimental SMTChecker;``, then you get additional
+safety warnings which are obtained by querying an SMT solver.
+The component does not yet support all features of the Solidity language
+and likely outputs many warnings. In case it reports unsupported
+features, the analysis may not be fully sound.
+
.. index:: source file, ! import
.. _import:
@@ -56,18 +117,27 @@ At a global level, you can use import statements of the following form:
This statement imports all global symbols from "filename" (and symbols imported there) into the
current global scope (different than in ES6 but backwards-compatible for Solidity).
+This simple form is not recommended for use, because it pollutes the namespace in an
+unpredictable way: If you add new top-level items inside "filename", they will automatically
+appear in all files that import like this from "filename". It is better to import specific
+symbols explicitly.
+
+The following example creates a new global symbol ``symbolName`` whose members are all
+the global symbols from ``"filename"``.
::
import * as symbolName from "filename";
-...creates a new global symbol ``symbolName`` whose members are all the global symbols from ``"filename"``.
+If there is a naming collision, you can also rename symbols while importing.
+This code
+creates new global symbols ``alias`` and ``symbol2`` which reference ``symbol1`` and ``symbol2`` from inside ``"filename"``, respectively.
::
import {symbol1 as alias, symbol2} from "filename";
-...creates new global symbols ``alias`` and ``symbol2`` which reference ``symbol1`` and ``symbol2`` from ``"filename"``, respectively.
+
Another syntax is not part of ES6, but probably convenient:
@@ -93,6 +163,11 @@ It depends on the compiler (see below) how to actually resolve the paths.
In general, the directory hierarchy does not need to strictly map onto your local
filesystem, it can also map to resources discovered via e.g. ipfs, http or git.
+.. note::
+ Always use relative imports like ``import "./filename.sol";`` and avoid
+ using ``..`` in path specifiers. In the latter case, it is probably better to use
+ global paths and set up remappings as explained below.
+
Use in Actual Compilers
-----------------------
@@ -181,6 +256,11 @@ Single-line comments (``//``) and multi-line comments (``/*...*/``) are possible
multi-line comment.
*/
+.. note::
+ A single-line comment is terminated by any unicode line terminator
+ (LF, VF, FF, CR, NEL, LS or PS) in utf8 encoding. The terminator is still part of
+ the source code after the comment, so if it is not an ascii symbol
+ (these are NEL, LS and PS), it will lead to a parser error.
Additionally, there is another type of comment called a natspec comment,
for which the documentation is not yet written. They are written with a
@@ -196,7 +276,7 @@ for the two input parameters and two returned values.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
/** @title Shape calculator. */
contract ShapeCalculator {
diff --git a/docs/metadata.rst b/docs/metadata.rst
index 9c4f2574..c0613809 100644
--- a/docs/metadata.rst
+++ b/docs/metadata.rst
@@ -93,15 +93,16 @@ explanatory purposes.
}
}
+.. warning::
+ Since the bytecode of the resulting contract contains the metadata hash, any
+ change to the metadata results in a change of the bytecode. This includes
+ changes to a filename or path, and since the metadata includes a hash of all the
+ sources used, a single whitespace change results in different metadata, and
+ different bytecode.
+
.. note::
Note the ABI definition above has no fixed order. It can change with compiler versions.
-Since the bytecode of the resulting contract contains the metadata hash, any
-change to the metadata results in a change of the bytecode. This includes
-changes to a filename or path, and since the metadata includes a hash of all the
-sources used, a single whitespace change results in different metadata, and
-different bytecode.
-
Encoding of the Metadata Hash in the Bytecode
=============================================
@@ -117,19 +118,28 @@ to the end of the deployed bytecode::
So in order to retrieve the data, the end of the deployed bytecode can be checked
to match that pattern and use the Swarm hash to retrieve the file.
+.. note::
+ The compiler currently uses the "swarm version 0" hash of the metadata,
+ but this might change in the future, so do not rely on this sequence
+ to start with ``0xa1 0x65 'b' 'z' 'z' 'r' '0'``. We might also
+ add additional data to this CBOR structure, so the
+ best option is to use a proper CBOR parser.
+
+
Usage for Automatic Interface Generation and NatSpec
====================================================
The metadata is used in the following way: A component that wants to interact
-with a contract (e.g. Mist) retrieves the code of the contract, from that
+with a contract (e.g. Mist or any wallet) retrieves the code of the contract, from that
the Swarm hash of a file which is then retrieved.
That file is JSON-decoded into a structure like above.
The component can then use the ABI to automatically generate a rudimentary
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.
+Furthermore, the wallet can use the NatSpec user documentation to display a confirmation message to the user
+whenever they interact with the contract, together with requesting
+authorization for the transaction signature.
Additional information about Ethereum Natural Specification (NatSpec) can be found `here <https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format>`_.
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 87041be6..12603f2e 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -48,7 +48,7 @@ non-elementary type, the positions are found by adding an offset of ``keccak256(
So for the following contract snippet::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
struct s { uint a; uint b; }
@@ -64,20 +64,20 @@ The position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint25
Layout in Memory
****************
-Solidity reserves four 32 byte slots:
+Solidity reserves four 32-byte slots, with specific byte ranges (inclusive of endpoints) being used as follows:
-- ``0x00`` - ``0x3f``: scratch space for hashing methods
-- ``0x40`` - ``0x5f``: currently allocated memory size (aka. free memory pointer)
-- ``0x60`` - ``0x7f``: zero slot
+- ``0x00`` - ``0x3f`` (64 bytes): scratch space for hashing methods
+- ``0x40`` - ``0x5f`` (32 bytes): currently allocated memory size (aka. free memory pointer)
+- ``0x60`` - ``0x7f`` (32 bytes): zero slot
-Scratch space can be used between statements (ie. within inline assembly). The zero slot
+Scratch space can be used between statements (i.e. within inline assembly). The zero slot
is used as initial value for dynamic memory arrays and should never be written to
(the free memory pointer points to ``0x80`` initially).
Solidity always places new objects at the free memory pointer and memory is never freed (this might change in the future).
.. warning::
- There are some operations in Solidity that need a temporary memory area larger than 64 bytes and therefore will not fit into the scratch space. They will be placed where the free memory points to, but given their short lifecycle, the pointer is not updated. The memory may or may not be zeroed out. Because of this, one shouldn't expect the free memory to be zeroed out.
+ There are some operations in Solidity that need a temporary memory area larger than 64 bytes and therefore will not fit into the scratch space. They will be placed where the free memory points to, but given their short lifetime, the pointer is not updated. The memory may or may not be zeroed out. Because of this, one shouldn't expect the free memory to point to zeroed out memory.
While it may seem like a good idea to use ``msize`` to arrive at a definitely zeroed out memory area, using such a pointer non-temporarily without updating the free memory pointer can have adverse results.
@@ -242,7 +242,6 @@ Tips and Tricks
* Use shorter types for struct elements and sort them such that short types are grouped together. This can lower the gas costs as multiple ``SSTORE`` operations might be combined into a single (``SSTORE`` costs 5000 or 20000 gas, so this is what you want to optimise). Use the gas price estimator (with optimiser enabled) to check!
* Make your state variables public - the compiler will create :ref:`getters <visibility-and-getters>` for you automatically.
* If you end up checking conditions on input or state a lot at the beginning of your functions, try using :ref:`modifiers`.
-* If your contract has a function called ``send`` but you want to use the built-in send-function, use ``address(contractVariable).send(amount)``.
* Initialize storage structs with a single assignment: ``x = MyStruct({a: 1, b: 2});``
.. note::
@@ -278,7 +277,7 @@ The following is the order of precedence for operators, listed in order of evalu
+------------+-------------------------------------+--------------------------------------------+
| *2* | Prefix increment and decrement | ``++``, ``--`` |
+ +-------------------------------------+--------------------------------------------+
-| | Unary plus and minus | ``+``, ``-`` |
+| | Unary minus | ``-`` |
+ +-------------------------------------+--------------------------------------------+
| | Unary operations | ``delete`` |
+ +-------------------------------------+--------------------------------------------+
@@ -322,46 +321,42 @@ The following is the order of precedence for operators, listed in order of evalu
Global Variables
================
-- ``abi.decode(bytes encodedData, (...)) returns (...)``: :ref:`ABI <ABI>`-decodes the provided data. The types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))``
-- ``abi.encode(...) returns (bytes)``: :ref:`ABI <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)``: :ref:`ABI <ABI>`-encodes the given arguments
+- ``abi.decode(bytes memory encodedData, (...)) returns (...)``: :ref:`ABI <ABI>`-decodes the provided data. The types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))``
+- ``abi.encode(...) returns (bytes memory)``: :ref:`ABI <ABI>`-encodes the given arguments
+- ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments
+- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: :ref:`ABI <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)), ...)```
-- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``.
-- ``block.coinbase`` (``address``): current block miner's address
+- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature)), ...)```
+- ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
- ``block.gaslimit`` (``uint``): current block gaslimit
- ``block.number`` (``uint``): current block number
- ``block.timestamp`` (``uint``): current block timestamp
- ``gasleft() returns (uint256)``: remaining gas
- ``msg.data`` (``bytes``): complete calldata
-- ``msg.gas`` (``uint``): remaining gas - deprecated in version 0.4.21 and to be replaced by ``gasleft()``
-- ``msg.sender`` (``address``): sender of the message (current call)
+- ``msg.sender`` (``address payable``): sender of the message (current call)
- ``msg.value`` (``uint``): number of wei sent with the message
- ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``)
- ``tx.gasprice`` (``uint``): gas price of the transaction
-- ``tx.origin`` (``address``): sender of the transaction (full call chain)
+- ``tx.origin`` (``address payable``): sender of the transaction (full call chain)
- ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error)
- ``require(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component)
-- ``require(bool condition, string message)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component). Also provide error message.
+- ``require(bool condition, string memory message)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component). Also provide error message.
- ``revert()``: abort execution and revert state changes
-- ``revert(string message)``: abort execution and revert state changes providing an explanatory string
+- ``revert(string memory message)``: abort execution and revert state changes providing an explanatory string
- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks
-- ``keccak256(bytes memory) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the input
-- ``sha3(bytes memory) returns (bytes32)``: an alias to ``keccak256``
+- ``keccak256(bytes memory) returns (bytes32)``: compute the Keccak-256 hash of the input
- ``sha256(bytes memory) returns (bytes32)``: compute the SHA-256 hash of the input
- ``ripemd160(bytes memory) returns (bytes20)``: compute the RIPEMD-160 hash of the input
- ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error
- ``addmod(uint x, uint y, uint k) returns (uint)``: compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0.
- ``mulmod(uint x, uint y, uint k) returns (uint)``: compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0.
-- ``this`` (current contract's type): the current contract, explicitly convertible to ``address``
+- ``this`` (current contract's type): the current contract, explicitly convertible to ``address`` or ``address payable``
- ``super``: the contract one level higher in the inheritance hierarchy
-- ``selfdestruct(address recipient)``: destroy the current contract, sending its funds to the given address
-- ``suicide(address recipient)``: a deprecated alias to ``selfdestruct``
+- ``selfdestruct(address payable recipient)``: destroy the current contract, sending its funds to the given address
- ``<address>.balance`` (``uint256``): balance of the :ref:`address` in Wei
-- ``<address>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure
-- ``<address>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
+- ``<address payable>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure
+- ``<address payable>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
.. note::
Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness,
@@ -380,6 +375,11 @@ Global Variables
You can only access the hashes of the most recent 256 blocks, all other
values will be zero.
+.. note::
+ In version 0.5.0, the following aliases were removed: ``suicide`` as alias for ``selfdestruct``,
+ ``msg.gas`` as alias for ``gasleft``, ``block.blockhash`` as alias for ``blockhash`` and
+ ``sha3`` as alias for ``keccak256``.
+
.. index:: visibility, public, private, external, internal
Function Visibility Specifiers
diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst
index 3bcd9566..bd06276b 100644
--- a/docs/security-considerations.rst
+++ b/docs/security-considerations.rst
@@ -55,7 +55,7 @@ complete contract):
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract Fund {
@@ -78,7 +78,7 @@ as it uses ``call`` which forwards all remaining gas by default:
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract Fund {
@@ -97,7 +97,7 @@ outlined further below:
::
- pragma solidity ^0.4.11;
+ pragma solidity >=0.4.11 <0.6.0;
contract Fund {
/// Mapping of ether shares of the contract.
@@ -136,15 +136,16 @@ Sending and Receiving Ether
- If a contract receives Ether (without a function being called), the fallback function is executed.
If it does not have a fallback function, the Ether will be rejected (by throwing an exception).
During the execution of the fallback function, the contract can only rely
- on the "gas stipend" it is passed (2300 gas) being available to it at that time. This stipend is not enough to access storage in any way.
+ on the "gas stipend" it is passed (2300 gas) being available to it at that time. This stipend is not enough to modify storage
+ (do not take this for granted though, the stipend might change with future hard forks).
To be sure that your contract can receive Ether in that way, check the gas requirements of the fallback function
(for example in the "details" section in Remix).
- There is a way to forward more gas to the receiving contract using
``addr.call.value(x)("")``. This is essentially the same as ``addr.transfer(x)``,
only that it forwards all remaining gas and opens up the ability for the
- recipient to perform more expensive actions (and it only returns a failure code
- and does not automatically propagate the error). This might include calling back
+ recipient to perform more expensive actions (and it returns a failure code
+ instead of automatically propagating the error). This might include calling back
into the sending contract or other state changes you might not have thought of.
So it allows for great flexibility for honest users but also for malicious actors.
@@ -182,7 +183,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
@@ -192,7 +193,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
owner = msg.sender;
}
- function transferTo(address dest, uint amount) public {
+ function transferTo(address payable dest, uint amount) public {
require(tx.origin == owner);
dest.transfer(amount);
}
@@ -202,14 +203,14 @@ Now someone tricks you into sending ether to the address of this attack wallet:
::
- pragma solidity >0.4.24;
+ pragma solidity >0.4.99 <0.6.0;
interface TxUserWallet {
- function transferTo(address dest, uint amount) external;
+ function transferTo(address payable dest, uint amount) external;
}
contract TxAttackWallet {
- address owner;
+ address payable owner;
constructor() public {
owner = msg.sender;
@@ -223,6 +224,26 @@ Now someone tricks you into sending ether to the address of this attack wallet:
If your wallet had checked ``msg.sender`` for authorization, it would get the address of the attack wallet, instead of the owner address. But by checking ``tx.origin``, it gets the original address that kicked off the transaction, which is still the owner address. The attack wallet instantly drains all your funds.
+
+Two's Complement / Underflows / Overflows
+=========================================
+
+As in many programming languages, Solidity's integer types are not actually integers.
+They resemble integers when the values are small, but behave differently if the numbers are larger.
+For example, the following is true: ``uint8(255) + uint8(1) == 0``. This situation is called
+an *overflow*. It occurs when an operation is performed that requires a fixed size variable
+to store a number (or piece of data) that is outside the range of the variable's data type.
+An *underflow* is the converse situation: ``uint8(0) - uint8(1) == 255``.
+
+In general, read about the limits of two's complement representation, which even has some
+more special edge cases for signed numbers.
+
+Try to use ``require`` to limit the size of inputs to a reasonable range and use the
+:ref:`SMT checker<smt_checker>` to find potential overflows, or
+use a library like
+`SafeMath<https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol>`
+if you want all overflows to cause a revert.
+
Minor Details
=============
@@ -246,12 +267,8 @@ implications, there might be another issue buried beneath it.
Any compiler warning we issue can be silenced by slight changes to the
code.
-Also try to enable the "0.5.0" safety features as early as possible
-by adding ``pragma experimental "v0.5.0";``. Note that in this case,
-the word ``experimental`` does not mean that the safety features are in any
-way risky, it is just a way to enable some features that are
-not yet part of the latest version of Solidity due to backwards
-compatibility.
+Always use the latest version of the compiler to be notified about all recently
+introduced warnings.
Restrict the Amount of Ether
============================
@@ -305,6 +322,12 @@ of "failsafe" mode, which, for example, disables most of the features, hands ove
control to a fixed and trusted third party or just converts the contract into
a simple "give me back my money" contract.
+Ask for Peer Review
+===================
+
+The more people examine a piece of code, the more issues are found.
+Asking people to review your code also helps as a cross-check to find out whether your code
+is easy to understand - a very important criterion for good smart contracts.
*******************
Formal Verification
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index 72b3581b..1bbd42f8 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -36,7 +36,7 @@ of votes.
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
/// @title Voting with delegation.
contract Ballot {
@@ -220,18 +220,18 @@ bid. If the highest bid is raised, the previously
highest bidder gets her money back.
After the end of the bidding period, the
contract has to be called manually for the
-beneficiary to receive his money - contracts cannot
+beneficiary to receive their money - contracts cannot
activate themselves.
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract SimpleAuction {
// Parameters of the auction. Times are either
// absolute unix timestamps (seconds since 1970-01-01)
// or time periods in seconds.
- address public beneficiary;
+ address payable public beneficiary;
uint public auctionEndTime;
// Current state of the auction.
@@ -241,10 +241,11 @@ activate themselves.
// Allowed withdrawals of previous bids
mapping(address => uint) pendingReturns;
- // Set to true at the end, disallows any change
+ // Set to true at the end, disallows any change.
+ // By default initialized to `false`.
bool ended;
- // Events that will be fired on changes.
+ // Events that will be emitted on changes.
event HighestBidIncreased(address bidder, uint amount);
event AuctionEnded(address winner, uint amount);
@@ -258,7 +259,7 @@ activate themselves.
/// beneficiary address `_beneficiary`.
constructor(
uint _biddingTime,
- address _beneficiary
+ address payable _beneficiary
) public {
beneficiary = _beneficiary;
auctionEndTime = now + _biddingTime;
@@ -372,7 +373,7 @@ is the same as the one provided during the bidding period.
Another challenge is how to make the auction
**binding and blind** at the same time: The only way to
prevent the bidder from just not sending the money
-after he won the auction is to make her send it
+after they won the auction is to make her send it
together with the bid. Since value transfers cannot
be blinded in Ethereum, anyone can see the value.
@@ -396,7 +397,7 @@ high or low invalid bids.
uint deposit;
}
- address public beneficiary;
+ address payable public beneficiary;
uint public biddingEnd;
uint public revealEnd;
bool public ended;
@@ -421,7 +422,7 @@ high or low invalid bids.
constructor(
uint _biddingTime,
uint _revealTime,
- address _beneficiary
+ address payable _beneficiary
) public {
beneficiary = _beneficiary;
biddingEnd = now + _biddingTime;
@@ -541,12 +542,12 @@ Safe Remote Purchase
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract Purchase {
uint public value;
- address public seller;
- address public buyer;
+ address payable public seller;
+ address payable public buyer;
enum State { Created, Locked, Inactive }
State public state;
@@ -792,7 +793,7 @@ The full contract
::
- pragma solidity ^0.4.24;
+ pragma solidity >=0.4.24 <0.6.0;
contract ReceiverPays {
address owner = msg.sender;
@@ -987,14 +988,14 @@ The full contract
::
- pragma solidity ^0.4.24;
+ pragma solidity >=0.4.24 <0.6.0;
contract SimplePaymentChannel {
- address public sender; // The account sending payments.
- address public recipient; // The account receiving the payments.
+ address payable public sender; // The account sending payments.
+ address payable public recipient; // The account receiving the payments.
uint256 public expiration; // Timeout in case the recipient never closes.
- constructor (address _recipient, uint256 duration)
+ constructor (address payable _recipient, uint256 duration)
public
payable
{
diff --git a/docs/solidity-in-depth.rst b/docs/solidity-in-depth.rst
index b6217b47..ddfddb77 100644
--- a/docs/solidity-in-depth.rst
+++ b/docs/solidity-in-depth.rst
@@ -4,7 +4,7 @@ Solidity in Depth
This section should provide you with all you need to know about Solidity.
If something is missing here, please contact us on
-`Gitter <https://gitter.im/ethereum/solidity>`_ or make a pull request on
+`Gitter <https://gitter.im/ethereum/solidity>`_ or create a pull request on
`Github <https://github.com/ethereum/solidity/pulls>`_.
.. toctree::
@@ -18,3 +18,4 @@ If something is missing here, please contact us on
contracts.rst
assembly.rst
miscellaneous.rst
+ 050-breaking-changes.rst
diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst
index ae349055..582e5338 100644
--- a/docs/structure-of-a-contract.rst
+++ b/docs/structure-of-a-contract.rst
@@ -11,16 +11,22 @@ Each contract can contain declarations of :ref:`structure-state-variables`, :ref
:ref:`structure-function-modifiers`, :ref:`structure-events`, :ref:`structure-struct-types` and :ref:`structure-enum-types`.
Furthermore, contracts can inherit from other contracts.
+There are also special kinds of contracts called :ref:`libraries<libraries>` and :ref:`interfaces<interfaces>`.
+
+The section about :ref:`contracts<contracts>` contains more details than this section,
+which serves to provide a quick overview.
+
.. _structure-state-variables:
State Variables
===============
-State variables are values which are permanently stored in contract storage.
+State variables are variables whose values are permanently stored in contract
+storage.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract SimpleStorage {
uint storedData; // State variable
@@ -40,7 +46,7 @@ Functions are the executable units of code within a contract.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract SimpleAuction {
function bid() public payable { // Function
@@ -49,7 +55,7 @@ Functions are the executable units of code within a contract.
}
:ref:`function-calls` can happen internally or externally
-and have different levels of visibility (:ref:`visibility-and-getters`)
+and have different levels of :ref:`visibility<visibility-and-getters>`
towards other contracts.
.. _structure-function-modifiers:
@@ -58,11 +64,11 @@ Function Modifiers
==================
Function modifiers can be used to amend the semantics of functions in a declarative way
-(see :ref:`modifiers` in contracts section).
+(see :ref:`modifiers` in the contracts section).
::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract Purchase {
address public seller;
@@ -89,7 +95,7 @@ Events are convenience interfaces with the EVM logging facilities.
::
- pragma solidity ^0.4.21;
+ pragma solidity >=0.4.21 <0.6.0;
contract SimpleAuction {
event HighestBidIncreased(address bidder, uint amount); // Event
@@ -113,7 +119,7 @@ Structs are custom defined types that can group several variables (see
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Ballot {
struct Voter { // Struct
@@ -134,7 +140,7 @@ Enums can be used to create custom types with a finite set of 'constant values'
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Purchase {
enum State { Created, Locked, Inactive } // Enum
diff --git a/docs/style-guide.rst b/docs/style-guide.rst
index d2de5287..7b48ccad 100644
--- a/docs/style-guide.rst
+++ b/docs/style-guide.rst
@@ -52,7 +52,7 @@ Surround top level declarations in solidity source with two blank lines.
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
// ...
@@ -70,7 +70,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
// ...
@@ -89,7 +89,7 @@ Blank lines may be omitted between groups of related one-liners (such as stub fu
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
function spam() public pure;
@@ -109,7 +109,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
function spam() public pure {
@@ -237,7 +237,7 @@ Import statements should always be placed at the top of the file.
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
import "./Owned.sol";
@@ -251,7 +251,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
// ...
@@ -283,7 +283,7 @@ Within a grouping, place the ``view`` and ``pure`` functions last.
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
constructor() public {
@@ -315,7 +315,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract A {
@@ -411,7 +411,7 @@ should:
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Coin {
struct Bank {
@@ -422,7 +422,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract Coin
{
@@ -723,7 +723,7 @@ manner as modifiers if the function declaration is long or hard to read.
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// Base contracts just to make this compile
contract B {
@@ -755,7 +755,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// Base contracts just to make this compile
contract B {
@@ -874,6 +874,29 @@ No::
x = y+z;
x +=1;
+***************
+Order of Layout
+***************
+
+Layout contract elements in the following order:
+
+1. Pragma statements
+2. Import statements
+3. Interfaces
+4. Libraries
+5. Contracts
+
+Inside each contract, library or interface, use the following order:
+
+1. Type declarations
+2. State variables
+3. Events
+4. Functions
+
+.. note::
+
+ It might be clearer to declare types close to their use in events or state
+ variables.
******************
Naming Conventions
@@ -932,7 +955,7 @@ As shown in the example below, if the contract name is `Congress` and the librar
Yes::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// Owned.sol
contract Owned {
@@ -961,7 +984,7 @@ Yes::
No::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// owned.sol
contract owned {
diff --git a/docs/types.rst b/docs/types.rst
index 03fd36d9..e265e668 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -50,14 +50,25 @@ Operators:
* Comparisons: ``<=``, ``<``, ``==``, ``!=``, ``>=``, ``>`` (evaluate to ``bool``)
* Bit operators: ``&``, ``|``, ``^`` (bitwise exclusive or), ``~`` (bitwise negation)
-* Arithmetic operators: ``+``, ``-``, unary ``-``, unary ``+``, ``*``, ``/``, ``%`` (remainder), ``**`` (exponentiation), ``<<`` (left shift), ``>>`` (right shift)
+* Shift operators: ``<<`` (left shift), ``>>`` (right shift)
+* Arithmetic operators: ``+``, ``-``, unary ``-``, ``*``, ``/``, ``%`` (modulo), ``**`` (exponentiation)
-Division always truncates (it is just compiled to the ``DIV`` opcode of the EVM), but it does not truncate if both
-operators are :ref:`literals<rational_literals>` (or literal expressions).
-Division by zero and modulus with zero throws a runtime exception.
+Comparisons
+^^^^^^^^^^^
-The result of a shift operation is the type of the left operand. The
+The value of a comparison is the one obtained by comparing the integer value.
+
+Bit operations
+^^^^^^^^^^^^^^
+
+Bit operations are performed on the two's complement representation of the number.
+This means that, for example ``~int256(0) == int256(-1)``.
+
+Shifts
+^^^^^^
+
+The result of a shift operation has the type of the left operand. The
expression ``x << y`` is equivalent to ``x * 2**y``, and, for positive integers,
``x >> y`` is equivalent to ``x / 2**y``. For negative ``x``, ``x >> y``
is equivalent to dividing by a power of ``2`` while rounding down (towards negative infinity).
@@ -67,6 +78,64 @@ Shifting by a negative amount throws a runtime exception.
Before version ``0.5.0`` a right shift ``x >> y`` for negative ``x`` was equivalent to ``x / 2**y``,
i.e. right shifts used rounding towards zero instead of rounding towards negative infinity.
+Addition, Subtraction and Multiplication
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Addition, subtraction and multiplication have the usual semantics.
+They wrap in two's complement representation, meaning that
+for example ``uint256(0) - uint256(1) == 2**256 - 1``. You have to take these overflows
+into account when designing safe smart contracts.
+
+The expression ``-x`` is equivalent to ``(T(0) - x)`` where
+``T`` is the type of ``x``. This means that ``-x`` will not be negative
+if the type of ``x`` is an unsigned integer type. Also, ``-x`` can be
+positive if ``x`` is negative. There is another caveat also resulting
+from two's complement representation::
+
+ int x = -2**255;
+ assert(-x == x);
+
+This means that even if a number is negative, you cannot assume that
+its negation will be positive.
+
+
+Division
+^^^^^^^^
+
+Since the type of the result of an operation is always the type of one of
+the operands, division on integers always results in an integer.
+In Solidity, division rounds towards zero. This mean that ``int256(-5) / int256(2) == int256(-2)``.
+
+Note that in contrast, division on :ref:`literals<rational_literals>` results in fractional values
+of arbitrary precision.
+
+.. note::
+ Division by zero causes a failing assert.
+
+Modulo
+^^^^^^
+
+The modulo operation ``a % n`` yields the remainder ``r`` after the division of the operand ``a``
+by the operand ``n``, where ``q = int(a / n)`` and ``r = a - (n * q)``. This means that modulo
+results in the same sign as its left operand (or zero) and ``a % n == -(abs(a) % n)`` holds for negative ``a``:
+
+ * ``int256(5) % int256(2) == int256(1)``
+ * ``int256(5) % int256(-2) == int256(1)``
+ * ``int256(-5) % int256(2) == int256(-1)``
+ * ``int256(-5) % int256(-2) == int256(-1)``
+
+.. note::
+ Modulo with zero causes a failing assert.
+
+Exponentiation
+^^^^^^^^^^^^^^
+
+Exponentiation is only available for unsigned types. Please take care that the types
+you are using are large enough to hold the result and prepare for potential wrapping behaviour.
+
+.. note::
+ Note that ``0**0`` is defined by the EVM as ``1``.
+
.. index:: ! ufixed, ! fixed, ! fixed point number
Fixed Point Numbers
@@ -83,7 +152,7 @@ the type and ``N`` represents how many decimal points are available. ``M`` must
Operators:
* Comparisons: ``<=``, ``<``, ``==``, ``!=``, ``>=``, ``>`` (evaluate to ``bool``)
-* Arithmetic operators: ``+``, ``-``, unary ``-``, unary ``+``, ``*``, ``/``, ``%`` (remainder)
+* Arithmetic operators: ``+``, ``-``, unary ``-``, ``*``, ``/``, ``%`` (modulo)
.. note::
The main difference between floating point (``float`` and ``double`` in many languages, more precisely IEEE 754 numbers) and fixed point numbers is
@@ -98,7 +167,34 @@ Operators:
Address
-------
-``address``: Holds a 20 byte value (size of an Ethereum address). Address types also have members and serve as a base for all contracts.
+The address type comes in two flavours, which are largely identical:
+
+ - ``address``: Holds a 20 byte value (size of an Ethereum address).
+ - ``address payable``: Same as ``address``, but with the additional members ``transfer`` and ``send``.
+
+The idea behind this distinction is that ``address payable`` is an address you can send Ether to,
+while a plain ``address`` cannot be sent Ether.
+
+Type conversions:
+
+Implicit conversions from ``address payable`` to ``address`` are allowed, whereas conversions from ``address`` to ``address payable`` are
+not possible (the only way to perform such a conversion is by using an intermediate conversion to ``uint160``).
+
+:ref:`Address literals<address_literals>` can be implicitly converted to ``address payable``.
+
+Explicit conversions to and from ``address`` are allowed for integers, integer literals, ``bytes20`` and contract types with the following
+caveat:
+Conversions of the form ``address payable(x)`` are not allowed. Instead the result of a conversion of the form ``address(x)``
+has the type ``address payable``, if ``x`` is of integer or fixed bytes type, a literal or a contract with a payable fallback function.
+If ``x`` is a contract without payable fallback function, then ``address(x)`` will be of type ``address``.
+In external function signatures ``address`` is used for both the ``address`` and the ``address payable`` type.
+
+.. note::
+ It might very well be that you do not need to care about the distinction between ``address``
+ and ``address payable`` and just use ``address`` everywhere. For example,
+ if you are using the :ref:`withdrawal pattern<withdrawal_pattern>`, you can (and should) store the
+ address itself as ``address``, because you invoke the ``transfer`` function on
+ ``msg.sender``, which is an ``address payable``.
Operators:
@@ -113,26 +209,32 @@ Operators:
or you can use ``address(uint160(uint256(b)))``, which results in ``0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc``.
.. note::
- Starting with version 0.5.0 contracts do not derive from the address type, but can still be explicitly converted to address.
+ The distinction between ``address`` and ``address payable`` was introduced with version 0.5.0.
+ Also starting from that version, contracts do not derive from the address type, but can still be explicitly converted to
+ ``address`` or to ``address payable``, if they have a payable fallback function.
.. _members-of-addresses:
Members of Addresses
^^^^^^^^^^^^^^^^^^^^
-* ``balance`` and ``transfer``
+For a quick reference of all members of address, see :ref:`address_related`.
-For a quick reference, see :ref:`address_related`.
+* ``balance`` and ``transfer``
It is possible to query the balance of an address using the property ``balance``
-and to send Ether (in units of wei) to an address using the ``transfer`` function:
+and to send Ether (in units of wei) to a payable address using the ``transfer`` function:
::
- address x = 0x123;
- address myAddress = this;
+ address payable x = address(0x123);
+ address myAddress = address(this);
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);
+The ``transfer`` function fails if the balance of the current contract is not large enough
+or if the Ether transfer is rejected by the receiving account. The ``transfer`` function
+reverts on failure.
+
.. note::
If ``x`` is a contract address, its code (more specifically: its :ref:`fallback-function`, if present) will be executed together with the ``transfer`` call (this is a feature of the EVM and cannot be prevented). If that execution runs out of gas or fails in any way, the Ether transfer will be reverted and the current contract will stop with an exception.
@@ -146,14 +248,23 @@ 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``, ``delegatecall`` and ``staticcall``
+* ``call``, ``delegatecall`` and ``staticcall``
-Furthermore, to interface with contracts that do not adhere to the ABI,
+In order to interface with contracts that do not adhere to the ABI,
or to get more direct control over the encoding,
-the function ``call`` is provided which takes a single byte array as input.
+the functions ``call``, ``delegatecall`` and ``staticcall`` are provided.
+They all take a single ``bytes memory`` argument as input and
+return the success condition (as a ``bool``) and the returned data
+(``bytes memory``).
The functions ``abi.encode``, ``abi.encodePacked``, ``abi.encodeWithSelector``
and ``abi.encodeWithSignature`` can be used to encode structured data.
+Example::
+
+ bytes memory payload = abi.encodeWithSignature("register(string)", "MyName");
+ (bool success, bytes memory returnData) = address(nameReg).call(payload);
+ require(success);
+
.. warning::
All these functions are low-level functions and should be used with care.
Specifically, any unknown contract might be malicious and if you call it, you
@@ -167,8 +278,6 @@ and ``abi.encodeWithSignature`` can be used to encode structured data.
arbitrary arguments and would also handle a first argument of type
``bytes4`` differently. These edge cases were removed in version 0.5.0.
-``call`` returns a boolean indicating whether the invoked function terminated (``true``) or caused an EVM exception (``false``). It is not possible to access the actual data returned with plain Solidity. However, using inline assembly it is possible to make a raw ``call`` and access the actual data returned with the ``returndatacopy`` instruction.
-
It is possible to adjust the supplied gas with the ``.gas()`` modifier::
namReg.call.gas(1000000)(abi.encodeWithSignature("register(string)", "MyName"));
@@ -181,17 +290,14 @@ Lastly, these modifiers can be combined. Their order does not matter::
nameReg.call.gas(1000000).value(1 ether)(abi.encodeWithSignature("register(string)", "MyName"));
-.. note::
- It is not yet possible to use the gas or value modifiers on overloaded functions.
+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.
- A workaround is to introduce a special case for gas and value and just re-check
- whether they are present at the point of overload resolution.
-
-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.
+.. note::
+ 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. This function was removed in version 0.5.0.
-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.
+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.
+All three functions ``call``, ``delegatecall`` 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``.
@@ -199,9 +305,6 @@ The ``.gas()`` option is available on all three methods, while the ``.value()``
All contracts can be converted to ``address`` type, so it is possible to query the balance of the
current contract using ``address(this).balance``.
-.. note::
- The use of ``callcode`` is discouraged and will be removed in the future.
-
.. index:: ! contract type, ! type; contract
.. _contract_types:
@@ -210,12 +313,19 @@ Contract Types
--------------
Every :ref:`contract<contracts>` defines its own type.
-You can implicitly convert contracts to contracts they inherit from,
-and explicitly convert them to and from the ``address`` type.
+You can implicitly convert contracts to contracts they inherit from.
+Contracts can be explicitly converted to and from all other contract types
+and the ``address`` type.
+
+Explicit conversion to and from the ``address payable`` type
+is only possible if the contract type has a payable fallback function.
+The conversion is still performed using ``address(x)`` and not
+using ``address payable(x)``. You can find more information in the section about
+the :ref:`address type<address>`.
.. note::
- Starting with version 0.5.0 contracts do not derive from the address type,
- but can still be explicitly converted to address.
+ Before version 0.5.0, contracts directly derived from the address type
+ and there was no distinction between ``address`` and ``address payable``.
If you declare a local variable of contract type (`MyContract c`), you can call
functions on that contract. Take care to assign it from somewhere that is the
@@ -238,25 +348,29 @@ including public state variables.
Fixed-size byte arrays
----------------------
-``bytes1``, ``bytes2``, ``bytes3``, ..., ``bytes32``. ``byte`` is an alias for ``bytes1``.
+The value types ``bytes1``, ``bytes2``, ``bytes3``, ..., ``bytes32``
+hold a sequence of bytes from one to up to 32.
+``byte`` is an alias for ``bytes1``.
Operators:
* Comparisons: ``<=``, ``<``, ``==``, ``!=``, ``>=``, ``>`` (evaluate to ``bool``)
-* Bit operators: ``&``, ``|``, ``^`` (bitwise exclusive or), ``~`` (bitwise negation), ``<<`` (left shift), ``>>`` (right shift)
+* Bit operators: ``&``, ``|``, ``^`` (bitwise exclusive or), ``~`` (bitwise negation)
+* Shift operators: ``<<`` (left shift), ``>>`` (right shift)
* Index access: If ``x`` is of type ``bytesI``, then ``x[k]`` for ``0 <= k < I`` returns the ``k`` th byte (read-only).
-The shifting operator works with any integer type as right operand (but will
-return the type of the left operand), which denotes the number of bits to shift by.
-Shifting by a negative amount will cause a runtime exception.
+The shifting operator works with any integer type as right operand (but
+returns the type of the left operand), which denotes the number of bits to shift by.
+Shifting by a negative amount causes a runtime exception.
Members:
* ``.length`` yields the fixed length of the byte array (read-only).
.. note::
- It is possible to use an array of bytes as ``byte[]``, but it is wasting a lot of space, 31 bytes every element,
- to be exact, when passing in calls. It is better to use ``bytes``.
+ The type ``byte[]`` is an array of bytes, but due to padding rules, it wastes
+ 31 bytes of space for each element (except in storage). It is better to use the ``bytes``
+ type instead.
Dynamically-sized byte array
----------------------------
@@ -274,7 +388,7 @@ Address Literals
----------------
Hexadecimal literals that pass the address checksum test, for example
-``0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF`` are of ``address`` type.
+``0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF`` are of ``address payable`` type.
Hexadecimal literals that are between 39 and 41 digits
long and do not pass the checksum test produce
a warning and are treated as regular rational number literals.
@@ -302,10 +416,11 @@ Examples include ``2e10``, ``-2e10``, ``2e-10``, ``2.5e1``.
Underscores can be used to separate the digits of a numeric literal to aid readability.
For example, decimal ``123_000``, hexadecimal ``0x2eff_abde``, scientific decimal notation ``1_2e345_678`` are all valid.
Underscores are only allowed between two digits and only one consecutive underscore is allowed.
-There is no additional semantic meaning added to a number literal containing underscores.
+There is no additional semantic meaning added to a number literal containing underscores,
+the underscores are ignored.
Number literal expressions retain arbitrary precision until they are converted to a non-literal type (i.e. by
-using them together with a non-literal expression).
+using them together with a non-literal expression or by explicit conversion).
This means that computations do not overflow and divisions do not truncate
in number literal expressions.
@@ -327,14 +442,15 @@ a non-rational number).
belong to the same number literal type for the rational number three.
.. warning::
- Division on integer literals used to truncate in earlier versions, but it will now convert into a rational number, i.e. ``5 / 2`` is not equal to ``2``, but to ``2.5``.
+ Division on integer literals used to truncate in Solidity prior to version 0.4.0, but it now converts into a rational number, i.e. ``5 / 2`` is not equal to ``2``, but to ``2.5``.
.. note::
Number literal expressions are converted into a non-literal type as soon as they are used with non-literal
- expressions. Even though we know that the value of the
- expression assigned to ``b`` in the following example evaluates to
- an integer, but the partial expression ``2.5 + a`` does not type check so the code
- does not compile
+ expressions. Disregarding types, the value of the expression assigned to ``b``
+ below evaluates to an integer. Because ``a`` is of type ``uint128``, the
+ expression ``2.5 + a`` has to have a proper type, though. Since there is no common type
+ for the type of ``2.5`` and ``uint128``, the Solidity compiler does not accept
+ this code.
::
@@ -342,22 +458,51 @@ a non-rational number).
uint128 b = 2.5 + a + 0.5;
.. index:: literal, literal;string, string
+.. _string_literals:
String Literals
---------------
-String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``). They do not imply trailing zeroes as in C; ``"foo"`` represents three bytes not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``.
+String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``). They do not imply trailing zeroes as in C; ``"foo"`` represents three bytes, not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``.
+
+String literals support the following escape characters:
+
+ - ``\<newline>`` (escapes an actual newline)
+ - ``\\`` (backslash)
+ - ``\'`` (single quote)
+ - ``\"`` (double quote)
+ - ``\b`` (backspace)
+ - ``\f`` (form feed)
+ - ``\n`` (newline)
+ - ``\r`` (carriage return)
+ - ``\t`` (tab)
+ - ``\v`` (vertical tab)
+ - ``\xNN`` (hex escape, see below)
+ - ``\uNNNN`` (unicode escape, see below)
-String literals support escape characters, such as ``\n``, ``\xNN`` and ``\uNNNN``. ``\xNN`` takes a hex value and inserts the appropriate byte, while ``\uNNNN`` takes a Unicode codepoint and inserts an UTF-8 sequence.
+``\xNN`` takes a hex value and inserts the appropriate byte, while ``\uNNNN`` takes a Unicode codepoint and inserts an UTF-8 sequence.
+
+The string in the following example has a length of ten bytes.
+It starts with a newline byte, followed by a double quote, a single
+quote a backslash character and then (without separator) the
+character sequence ``abcdef``.
+
+::
+
+ "\n\"\'\\abc\
+ def"
+
+Any unicode line terminator which is not a newline (i.e. LF, VF, FF, CR, NEL, LS, PS) is considered to
+terminate the string literal. Newline only terminates the string literal if it is not preceded by a ``\``.
.. index:: literal, bytes
Hexadecimal Literals
--------------------
-Hexademical Literals are prefixed with the keyword ``hex`` and are enclosed in double or single-quotes (``hex"001122FF"``). Their content must be a hexadecimal string and their value will be the binary representation of those values.
+Hexadecimal literals are prefixed with the keyword ``hex`` and are enclosed in double or single-quotes (``hex"001122FF"``). Their content must be a hexadecimal string and their value will be the binary representation of those values.
-Hexademical Literals behave like String Literals and have the same convertibility restrictions.
+Hexadecimal literals behave like :ref:`string literals <string_literals>` and have the same convertibility restrictions.
.. index:: enum
@@ -367,8 +512,9 @@ Enums
-----
Enums are one way to create a user-defined type in Solidity. They are explicitly convertible
-to and from all integer types but implicit conversion is not allowed. The explicit conversions
-check the value ranges at runtime and a failure causes an exception. Enums needs at least one member.
+to and from all integer types but implicit conversion is not allowed. The explicit conversion
+from integer checks at runtime that the value lies inside the range of the enum and causes a failing assert otherwise.
+Enums needs at least one member.
The data representation is the same as for enums in C: The options are represented by
subsequent unsigned integer values starting from ``0``.
@@ -376,7 +522,7 @@ subsequent unsigned integer values starting from ``0``.
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract test {
enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
@@ -436,6 +582,11 @@ omitted. Note that this only applies to function types. Visibility has
to be specified explicitly for functions defined in contracts, they
do not have a default.
+Conversions:
+
+A value of external function type can be explicitly converted to ``address``
+resulting in the address of the contract of the function.
+
A function type ``A`` is implicitly convertible to a function type ``B`` if and only if
their parameter types are identical, their return types are identical,
their internal/external property is identical and the state mutability of ``A``
@@ -445,7 +596,7 @@ is not more restrictive than the state mutability of ``B``. In particular:
- ``view`` functions can be converted to ``non-payable`` functions
- ``payable`` functions can be converted to ``non-payable`` functions
-No other conversions are possible.
+No other conversions between function types are possible.
The rule about ``payable`` and ``non-payable`` might be a little
confusing, but in essence, if a function is ``payable``, this means that it
@@ -453,8 +604,8 @@ also accepts a payment of zero Ether, so it also is ``non-payable``.
On the other hand, a ``non-payable`` function will reject Ether sent to it,
so ``non-payable`` functions cannot be converted to ``payable`` functions.
-If a function type variable is not initialized, calling it will result
-in an exception. The same happens if you call a function after using ``delete``
+If a function type variable is not initialised, calling it results
+in a failed assertion. The same happens if you call a function after using ``delete``
on it.
If external function types are used outside of the context of Solidity,
@@ -465,10 +616,12 @@ Note that public functions of the current contract can be used both as an
internal and as an external function. To use ``f`` as an internal function,
just use ``f``, if you want to use its external form, use ``this.f``.
-Additionally, public (or external) functions also have a special member called ``selector``,
+Members:
+
+Public (or external) functions also have a special member called ``selector``,
which returns the :ref:`ABI function selector <abi_function_selector>`::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract Selector {
function f() public pure returns (bytes4) {
@@ -478,7 +631,7 @@ which returns the :ref:`ABI function selector <abi_function_selector>`::
Example that shows how to use internal function types::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
library ArrayUtils {
// internal functions can be used in internal library functions because
@@ -529,7 +682,7 @@ Example that shows how to use internal function types::
Another example that uses external function types::
- pragma solidity ^0.4.22;
+ pragma solidity >=0.4.22 <0.6.0;
contract Oracle {
struct Request {
@@ -569,21 +722,27 @@ Another example that uses external function types::
.. index:: ! type;reference, ! reference type, storage, memory, location, array, struct
Reference Types
-==================
+===============
-Complex types, i.e. types which do not always fit into 256 bits have to be handled
-more carefully than the value-types we have already seen. Since copying
-them can be quite expensive, we have to think about whether we want them to be
-stored in **memory** (which is not persisting) or **storage** (where the state
-variables are held).
+Values of reference type can be modified through multiple different names.
+Contrast this with value types where you get an independent copy whenever
+a variable of value type is used. Because of that, reference types have to be handled
+more carefully than value types. Currently, reference types comprise structs,
+arrays and mappings. If you use a reference type, you always have to explicitly
+provide the data area where the type is stored: ``memory`` (whose lifetime is limited
+to a function call), ``storage`` (the location where the state variables are stored)
+or ``calldata`` (special data location that contains the function arguments,
+only available for external function call parameters).
+
+An assignment or type conversion that changes the data location will always incur an automatic copy operation,
+while assignments inside the same data location only copy in some cases for storage types.
.. _data-location:
Data location
-------------
-
-Every complex type, i.e. *arrays* and *structs*, has an additional
+Every reference type, i.e. *arrays* and *structs*, has an additional
annotation, the "data location", about where it is stored. There are three data locations:
``memory``, ``storage`` and ``calldata``. Calldata is only valid for parameters of external contract
functions and is required for this type of parameter. Calldata is a non-modifiable,
@@ -595,18 +754,18 @@ non-persistent area where function arguments are stored, and behaves mostly like
depending on the kind of variable, function type, etc., but all complex types must now give an explicit
data location.
-Data locations are important because they change how assignments behave:
-assignments between storage and memory and also to a state variable (even from other state variables)
-always create an independent copy.
-Assignments to local storage variables only assign a reference though, and
-this reference always points to the state variable even if the latter is changed
-in the meantime.
-On the other hand, assignments from a memory stored reference type to another
-memory-stored reference type do not create a copy.
+Data locations are not only relevant for persistency of data, but also for the semantics of assignments:
+assignments between storage and memory (or from calldata) always create an independent copy.
+Assignments from memory to memory only create references. This means that changes to one memory variable
+are also visible in all other memory variables that refer to the same data.
+Assignments from storage to a local storage variables also only assign a reference.
+In contrast, all other assignments to storage always copy. Examples for this case
+are assignments to state variables or to members of local variables of storage struct type, even
+if the local variable itself is just a reference.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract C {
uint[] x; // the data location of x is storage
@@ -632,13 +791,6 @@ memory-stored reference type do not create a copy.
function h(uint[] memory) public pure {}
}
-Summary
-^^^^^^^
-
-Forced data location:
- - parameters (not return) of external functions: calldata
- - state variables: storage
-
.. index:: ! array
.. _arrays:
@@ -647,9 +799,10 @@ Arrays
------
Arrays can have a compile-time fixed size or they can be dynamic.
-For storage arrays, the element type can be arbitrary (i.e. also other
-arrays, mappings or structs). For memory arrays, it cannot be a mapping and
-has to be an ABI type if it is an argument of a publicly-visible function.
+The are few restrictions for the element, it can also be
+another array, a mapping or a struct. The general restrictions for
+types apply, though, in that mappings can only be used in storage
+and publicly-visible functions need parameters that are ABI types.
An array of fixed size ``k`` and element type ``T`` is written as ``T[k]``,
an array of dynamic size as ``T[]``. As an example, an array of 5 dynamic
@@ -659,9 +812,13 @@ third dynamic array, you use ``x[2][1]`` (indices are zero-based and
access works in the opposite way of the declaration, i.e. ``x[2]``
shaves off one level in the type from the right).
+Accessing an array past its end causes a revert. If you want to add
+new elements, you have to use ``.push()`` or increase the ``.length``
+member (see below).
+
Variables of type ``bytes`` and ``string`` are special arrays. A ``bytes`` is similar to ``byte[]``,
-but it is packed tightly in calldata. ``string`` is equal to ``bytes`` but does not allow
-length or index access (for now).
+but it is packed tightly in calldata and memory. ``string`` is equal to ``bytes`` but does not allow
+length or index access.
So ``bytes`` should always be preferred over ``byte[]`` because it is cheaper.
As a rule of thumb, use ``bytes`` for arbitrary-length raw byte data and ``string``
for arbitrary-length string (UTF-8) data. If you can limit the length to a certain
@@ -681,14 +838,14 @@ The numeric index will become a required parameter for the getter.
Allocating Memory Arrays
^^^^^^^^^^^^^^^^^^^^^^^^
-Creating arrays with variable length in memory can be done using the ``new`` keyword.
+You can use the ``new`` keyword to create arrays with a runtime-dependent length in memory.
As opposed to storage arrays, it is **not** possible to resize memory arrays (e.g. by assigning to
the ``.length`` member). You either have to calculate the required size in advance
or create a new memory array and copy every element.
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function f(uint len) public pure {
@@ -710,7 +867,7 @@ assigned to a variable right away.
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract C {
function f() public pure {
@@ -724,14 +881,14 @@ assigned to a variable right away.
The type of an array literal is a memory array of fixed size whose base
type is the common type of the given elements. The type of ``[1, 2, 3]`` is
``uint8[3] memory``, because the type of each of these constants is ``uint8``.
-Because of that, it was necessary to convert the first element in the example
+Because of that, it is necessary to convert the first element in the example
above to ``uint``. Note that currently, fixed size memory arrays cannot
be assigned to dynamically-sized memory arrays, i.e. the following is not
possible:
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
// This will not compile.
contract C {
@@ -751,16 +908,31 @@ Members
^^^^^^^
**length**:
- Arrays have a ``length`` member to hold their number of elements.
- Dynamic arrays can be resized in storage (not in memory) by changing the
- ``.length`` member. This does not happen automatically when attempting to access elements outside the current length. The size of memory arrays is fixed (but dynamic, i.e. it can depend on runtime parameters) once they are created.
+ Arrays have a ``length`` member that contains their number of elements.
+ The length of memory arrays is fixed (but dynamic, i.e. it can depend on runtime parameters) once they are created.
+ For dynamically-sized arrays (only available for storage), this member can be assigned to resize the array.
+ Accessing elements outside the current length does not automatically resize the array and instead causes a failing assertion.
+ Increasing the length adds new zero-initialised elements to the array.
+ Reducing the length performs an implicit :ref:``delete`` on each of the removed elements.
**push**:
- Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``push`` that can be used to append an element at the end of the array. The function returns the new length.
+ Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``push`` that you can use to append an element at the end of the array. The element will be zero-initialised. The function returns the new length.
**pop**:
- Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``pop`` that can be used to remove an element from the end of the array.
+ Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``pop`` that you can use to remove an element from the end of the array. This also implicitly calls :ref:``delete`` on the removed element.
.. warning::
- It is not yet possible to use arrays of arrays in external functions.
+ If you use ``.length--`` on an empty array, it causes an underflow and
+ thus sets the length to ``2**256-1``.
+
+.. note::
+ Increasing the length of a storage array has constant gas costs because
+ storage is assumed to be zero-initialised, while decreasing
+ the length has at least linear cost (but in most cases worse than linear),
+ because it includes explicitly clearing the removed
+ elements similar to calling :ref:``delete`` on them.
+
+.. note::
+ It is not yet possible to use arrays of arrays in external functions
+ (but they are supported in public functions).
.. note::
In EVM versions before Byzantium, it was not possible to access
@@ -770,7 +942,7 @@ Members
::
- pragma solidity ^0.4.16;
+ pragma solidity >=0.4.16 <0.6.0;
contract ArrayContract {
uint[2**20] m_aLotOfIntegers;
@@ -778,15 +950,34 @@ Members
// dynamic array of pairs (i.e. of fixed size arrays of length two).
// Because of that, T[] is always a dynamic array of T, even if T
// itself is an array.
+ // Data location for all state variables is storage.
bool[2][] m_pairsOfFlags;
// newPairs is stored in memory - the only possibility
- // for public function arguments
+ // for public contract function arguments
function setAllFlagPairs(bool[2][] memory newPairs) public {
- // assignment to a storage array replaces the complete array
+ // assignment to a storage array performs a copy of ``newPairs`` and
+ // replaces the complete array ``m_pairsOfFlags``.
m_pairsOfFlags = newPairs;
}
+ struct StructType {
+ uint[] contents;
+ uint moreInfo;
+ }
+ StructType s;
+
+ function f(uint[] memory c) public {
+ // stores a reference to ``s`` in ``g``
+ StructType storage g = s;
+ // also changes ``s.moreInfo``.
+ g.moreInfo = 2;
+ // assigns a copy because ``g.contents``
+ // is not a local variable, but a member of
+ // a local variable.
+ g.contents = c;
+ }
+
function setFlagPair(uint index, bool flagA, bool flagB) public {
// access to a non-existing index will throw an exception
m_pairsOfFlags[index][0] = flagA;
@@ -850,7 +1041,7 @@ shown in the following example:
::
- pragma solidity ^0.4.11;
+ pragma solidity >=0.4.11 <0.6.0;
contract CrowdFunding {
// Defines a new type with two fields.
@@ -860,7 +1051,7 @@ shown in the following example:
}
struct Campaign {
- address beneficiary;
+ address payable beneficiary;
uint fundingGoal;
uint numFunders;
uint amount;
@@ -870,9 +1061,12 @@ shown in the following example:
uint numCampaigns;
mapping (uint => Campaign) campaigns;
- function newCampaign(address beneficiary, uint goal) public returns (uint campaignID) {
+ function newCampaign(address payable beneficiary, uint goal) public returns (uint campaignID) {
campaignID = numCampaigns++; // campaignID is return variable
- // Creates new struct and saves in storage. We leave out the mapping type.
+ // Creates new struct in memory and copies it to storage.
+ // We leave out the mapping type, because it is not valid in memory.
+ // If structs are copied (even from storage to storage), mapping types
+ // are always omitted, because they cannot be enumerated.
campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
}
@@ -902,11 +1096,12 @@ Struct types can be used inside mappings and arrays and they can itself
contain mappings and arrays.
It is not possible for a struct to contain a member of its own type,
-although the struct itself can be the value type of a mapping member.
+although the struct itself can be the value type of a mapping member
+or it can contain a dynamically-sized array of its type.
This restriction is necessary, as the size of the struct has to be finite.
Note how in all the functions, a struct type is assigned to a local variable
-(of the default storage data location).
+with data location ``storage``.
This does not copy the struct but only stores a reference so that assignments to
members of the local variable actually write to the state.
@@ -917,32 +1112,39 @@ assigning it to a local variable, as in
.. index:: !mapping
Mappings
-========
-
-Mapping types are declared as ``mapping(_KeyType => _ValueType)``.
-Here ``_KeyType`` can be almost any type except for a mapping, a dynamically sized array, a contract, a function, an enum and a struct.
-``_ValueType`` can actually be any type, including mappings.
-
-Mappings can be seen as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_ which are virtually initialized such that
-every possible key exists and is mapped to a value whose byte-representation is
-all zeros: a type's :ref:`default value <default-value>`. The similarity ends here, though: The key data is not actually stored
-in a mapping, only its ``keccak256`` hash used to look up the value.
-
-Because of this, mappings do not have a length or a concept of a key or value being "set".
-
-Mappings are only allowed for state variables (or as storage reference types
-in internal functions).
-
-It is possible to mark mappings ``public`` and have Solidity create a :ref:`getter <visibility-and-getters>`.
-The ``_KeyType`` will become a required parameter for the getter and it will
-return ``_ValueType``.
+--------
-The ``_ValueType`` can be a mapping too. The getter will have one parameter
-for each ``_KeyType``, recursively.
+You declare mapping types with the syntax ``mapping(_KeyType => _ValueType)``.
+The ``_KeyType`` can be any elementary type. This means it can be any of
+the built-in value types plus ``bytes`` and ``string``. User-defined
+or complex types like contract types, enums, mappings, structs and any array type
+apart from ``bytes`` and ``string`` are not allowed.
+``_ValueType`` can be any type, including mappings.
+
+You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised
+such that every possible key exists and is mapped to a value whose
+byte-representation is all zeros, a type's :ref:`default value <default-value>`. The similarity ends there, the key data is not stored in a
+mapping, only its ``keccak256`` hash is used to look up the value.
+
+Because of this, mappings do not have a length or a concept of a key or
+value being set.
+
+Mappings can only have a data location of ``storage`` and thus
+are allowed for state variables, as storage reference types
+in functions, or as parameters for library functions.
+They cannot be used as parameters or return parameters
+of contract functions that are publicly visible.
+
+You can mark variables of mapping type as ``public`` and Solidity creates a
+:ref:`getter <visibility-and-getters>` for you. The ``_KeyType`` becomes a
+parameter for the getter. If ``_ValueType`` is a value type or a struct,
+the getter returns ``_ValueType``.
+If ``_ValueType`` is an array or a mapping, the getter has one parameter for
+each ``_KeyType``, recursively. For example with a mapping:
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract MappingExample {
mapping(address => uint) public balances;
@@ -962,8 +1164,8 @@ for each ``_KeyType``, recursively.
.. note::
- Mappings are not iterable, but it is possible to implement a data structure on top of them.
- For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_.
+ Mappings are not iterable, but it is possible to implement a data structure
+ on top of them. For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_.
.. index:: assignment, ! delete, lvalue
@@ -977,15 +1179,17 @@ If ``a`` is an LValue (i.e. a variable or something that can be assigned to), th
delete
------
-``delete a`` assigns the initial value for the type to ``a``. I.e. for integers it is equivalent to ``a = 0``, but it can also be used on arrays, where it assigns a dynamic array of length zero or a static array of the same length with all elements reset. For structs, it assigns a struct with all members reset.
+``delete a`` assigns the initial value for the type to ``a``. I.e. for integers it is equivalent to ``a = 0``, but it can also be used on arrays, where it assigns a dynamic array of length zero or a static array of the same length with all elements reset. For structs, it assigns a struct with all members reset. In other words, the value of ``a`` after ``delete a`` is the same as if ``a`` would be declared without assignment, with the following caveat:
-``delete`` has no effect on whole mappings (as the keys of mappings may be arbitrary and are generally unknown). So if you delete a struct, it will reset all members that are not mappings and also recurse into the members unless they are mappings. However, individual keys and what they map to can be deleted.
+``delete`` has no effect on mappings (as the keys of mappings may be arbitrary and are generally unknown). So if you delete a struct, it will reset all members that are not mappings and also recurse into the members unless they are mappings. However, individual keys and what they map to can be deleted: If ``a`` is a mapping, then ``delete a[x]`` will delete the value stored at ``x``.
It is important to note that ``delete a`` really behaves like an assignment to ``a``, i.e. it stores a new object in ``a``.
+This distinction is visible when ``a`` is reference variable: It will only reset ``a`` itself, not the
+value it referred to previously.
::
- pragma solidity ^0.4.0;
+ pragma solidity >=0.4.0 <0.6.0;
contract DeleteExample {
uint data;
@@ -994,7 +1198,7 @@ It is important to note that ``delete a`` really behaves like an assignment to `
function f() public {
uint x = data;
delete x; // sets x to 0, does not affect data
- delete data; // sets data to 0, does not affect x which still holds a copy
+ delete data; // sets data to 0, does not affect x
uint[] storage y = dataArray;
delete dataArray; // this sets dataArray.length to zero, but as uint[] is a complex object, also
// y is affected which is an alias to the storage object
@@ -1023,12 +1227,15 @@ makes sense semantically and no information is lost: ``uint8`` is convertible to
(because ``uint256`` cannot hold e.g. ``-1``).
Any integer type that can be converted to ``uint160`` can also be converted to ``address``.
+For more details, please consult the sections about the types themselves.
+
Explicit Conversions
--------------------
If the compiler does not allow implicit conversion but you know what you are
doing, an explicit type conversion is sometimes possible. Note that this may
-give you some unexpected behaviour so be sure to test to ensure that the
+give you some unexpected behaviour and allows you to bypass some security
+features of the compiler, so be sure to test that the
result is what you want! Take the following example where you are converting
a negative ``int8`` to a ``uint``:
@@ -1127,3 +1334,5 @@ Addresses
As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum
test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type.
+
+Explicit conversions from ``bytes20`` or any integer type to ``address`` results in ``address payable``. \ No newline at end of file
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index 55911dc6..7f62e71e 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -7,15 +7,25 @@ Units and Globally Available Variables
Ether Units
===========
-A literal number can take a suffix of ``wei``, ``finney``, ``szabo`` or ``ether`` to convert between the subdenominations of Ether, where Ether currency numbers without a postfix are assumed to be Wei, e.g. ``2 ether == 2000 finney`` evaluates to ``true``.
+A literal number can take a suffix of ``wei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
+
+::
+
+ assert(1 wei == 1);
+ assert(1 szabo == 1e12);
+ assert(1 finney == 1e15);
+ assert(1 ether == 1e18);
+
+The only effect of the subdenomination suffix is a multiplication by a power of ten.
+
.. index:: time, seconds, minutes, hours, days, weeks, years
Time Units
==========
-Suffixes like ``seconds``, ``minutes``, ``hours``, ``days``, ``weeks`` and
-``years`` after literal numbers can be used to convert between units of time where seconds are the base
+Suffixes like ``seconds``, ``minutes``, ``hours``, ``days`` and ``weeks``
+after literal numbers can be used to specify units of time where seconds are the base
unit and units are considered naively in the following way:
* ``1 == 1 seconds``
@@ -23,7 +33,6 @@ unit and units are considered naively in the following way:
* ``1 hours == 60 minutes``
* ``1 days == 24 hours``
* ``1 weeks == 7 days``
- * ``1 years == 365 days``
Take care if you perform calendar calculations using these units, because
not every year equals 365 days and not even every day has 24 hours
@@ -32,7 +41,7 @@ Due to the fact that leap seconds cannot be predicted, an exact calendar
library has to be updated by an external oracle.
.. note::
- The suffix ``years`` has been deprecated due to the reasons above and cannot be used starting version 0.5.0.
+ The suffix ``years`` has been removed in version 0.5.0 due to the reasons above.
These suffixes cannot be applied to variables. If you want to
interpret some input variable in e.g. days, you can do it in the following way::
@@ -56,21 +65,20 @@ or are general-use utility functions.
Block and Transaction Properties
--------------------------------
-- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``.
-- ``block.coinbase`` (``address``): current block miner's address
+- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks
+- ``block.coinbase`` (``address payable``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
- ``block.gaslimit`` (``uint``): current block gaslimit
- ``block.number`` (``uint``): current block number
- ``block.timestamp`` (``uint``): current block timestamp as seconds since unix epoch
- ``gasleft() returns (uint256)``: remaining gas
-- ``msg.data`` (``bytes``): complete calldata
-- ``msg.gas`` (``uint``): remaining gas - deprecated in version 0.4.21 and to be replaced by ``gasleft()``
-- ``msg.sender`` (``address``): sender of the message (current call)
+- ``msg.data`` (``bytes calldata``): complete calldata
+- ``msg.sender`` (``address payable``): sender of the message (current call)
- ``msg.sig`` (``bytes4``): first four bytes of the calldata (i.e. function identifier)
- ``msg.value`` (``uint``): number of wei sent with the message
- ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``)
- ``tx.gasprice`` (``uint``): gas price of the transaction
-- ``tx.origin`` (``address``): sender of the transaction (full call chain)
+- ``tx.origin`` (``address payable``): sender of the transaction (full call chain)
.. note::
The values of all members of ``msg``, including ``msg.sender`` and
@@ -94,20 +102,28 @@ Block and Transaction Properties
You can only access the hashes of the most recent 256 blocks, all other
values will be zero.
+.. note::
+ The function ``blockhash`` was previously known as ``block.blockhash``. It was deprecated in
+ version 0.4.22 and removed in version 0.5.0.
+
+.. note::
+ The function ``gasleft`` was previously known as ``msg.gas``. It was deprecated in
+ version 0.4.21 and removed in version 0.5.0.
+
.. index:: abi, encoding, packed
ABI Encoding and Decoding Functions
-----------------------------------
-- ``abi.decode(bytes encodedData, (...)) returns (...)``: ABI-decodes the given data, while the types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))``
-- ``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.decode(bytes memory encodedData, (...)) returns (...)``: ABI-decodes the given data, while the types are given in parentheses as second argument. Example: ``(uint a, uint[2] memory b, bytes memory c) = abi.decode(data, (uint, uint[2], bytes))``
+- ``abi.encode(...) returns (bytes memory)``: ABI-encodes the given arguments
+- ``abi.encodePacked(...) returns (bytes memory)``: Performs :ref:`packed encoding <abi_packed_mode>` of the given arguments
+- ``abi.encodeWithSelector(bytes4 selector, ...) returns (bytes memory)``: ABI-encodes the given arguments starting from the second and prepends the given four-byte selector
+- ``abi.encodeWithSignature(string memory signature, ...) returns (bytes memory)``: Equivalent to ``abi.encodeWithSelector(bytes4(keccak256(bytes(signature))), ...)```
.. note::
- These encoding functions can be used to craft data for function calls without actually
- calling a function. Furthermore, ``keccak256(abi.encodePacked(a, b))`` is a way
+ These encoding functions can be used to craft data for external function calls without actually
+ calling an external function. Furthermore, ``keccak256(abi.encodePacked(a, b))`` is a way
to compute the hash of structured data (although be aware that it is possible to
craft a "hash collision" using different inputs types).
@@ -119,15 +135,18 @@ See the documentation about the :ref:`ABI <ABI>` and the
Error Handling
--------------
+See the dedicated section on :ref:`assert and require<assert-and-require>` for
+more details on error handling and when to use which function.
+
``assert(bool condition)``:
- invalidates the transaction if the condition is not met - to be used for internal errors.
+ causes an invalid opcode and thus state change reversion if the condition is not met - to be used for internal errors.
``require(bool condition)``:
reverts if the condition is not met - to be used for errors in inputs or external components.
-``require(bool condition, string message)``:
+``require(bool condition, string memory message)``:
reverts if the condition is not met - to be used for errors in inputs or external components. Also provides an error message.
``revert()``:
abort execution and revert state changes
-``revert(string reason)``:
+``revert(string memory reason)``:
abort execution and revert state changes, providing an explanatory string
.. index:: keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography,
@@ -140,39 +159,43 @@ Mathematical and Cryptographic Functions
``mulmod(uint x, uint y, uint k) returns (uint)``:
compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``. Assert that ``k != 0`` starting from version 0.5.0.
``keccak256(bytes memory) returns (bytes32)``:
- compute the Ethereum-SHA-3 (Keccak-256) hash of the input
+ compute the Keccak-256 hash of the input
``sha256(bytes memory) returns (bytes32)``:
compute the SHA-256 hash of the input
-``sha3(bytes memory) returns (bytes32)``:
- alias to ``keccak256``
``ripemd160(bytes memory) returns (bytes20)``:
compute RIPEMD-160 hash of the input
``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``:
recover the address associated with the public key from elliptic curve signature or return zero on error
(`example usage <https://ethereum.stackexchange.com/q/1777/222>`_)
+.. note::
+ Function ``ecrecover`` returns an ``address``, and not an ``address
+ payable``. See :ref:`address payable<address>` for conversion, in case you need
+ to transfer funds to the recovered address.
+
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.
+.. note::
+ There used to be an alias for ``keccak256`` called ``sha3``, which was removed in version 0.5.0.
+
.. index:: balance, send, transfer, call, callcode, delegatecall, staticcall
.. _address_related:
-Address Related
----------------
+Members of Address Types
+------------------------
``<address>.balance`` (``uint256``):
balance of the :ref:`address` in Wei
-``<address>.transfer(uint256 amount)``:
- send given amount of Wei to :ref:`address`, throws on failure, forwards 2300 gas stipend, not adjustable
-``<address>.send(uint256 amount) returns (bool)``:
+``<address payable>.transfer(uint256 amount)``:
+ send given amount of Wei to :ref:`address`, reverts on failure, forwards 2300 gas stipend, not adjustable
+``<address payable>.send(uint256 amount) returns (bool)``:
send given amount of Wei to :ref:`address`, returns ``false`` on failure, forwards 2300 gas stipend, not adjustable
-``<address>.call(bytes memory) returns (bool)``:
- issue low-level ``CALL`` with the given payload, returns ``false`` on failure, forwards all available gas, adjustable
-``<address>.callcode(bytes memory) returns (bool)``:
- 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
+``<address>.call(bytes memory) returns (bool, bytes memory)``:
+ issue low-level ``CALL`` with the given payload, returns success condition and return data, forwards all available gas, adjustable
+``<address>.delegatecall(bytes memory) returns (bool, bytes memory)``:
+ issue low-level ``DELEGATECALL`` with the given payload, returns success condition and return data, forwards all available gas, adjustable
+``<address>.staticcall(bytes memory) returns (bool, bytes memory)``:
+ issue low-level ``STATICCALL`` with the given payload, returns success condition and return data, forwards all available gas, adjustable
For more information, see the section on :ref:`address`.
@@ -187,14 +210,19 @@ For more information, see the section on :ref:`address`.
This is now forbidden and an explicit conversion to address must be done: ``address(this).balance``.
.. note::
- If storage variables are accessed via a low-level delegatecall, the storage layout of the two contracts
+ If state variables are accessed via a low-level delegatecall, the storage layout of the two contracts
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::
+ Prior to version 0.5.0, ``.call``, ``.delegatecall`` and ``.staticcall`` only returned the
+ success condition and not the return data.
.. note::
- The use of ``callcode`` is discouraged and will be removed in the future.
+ Prior to version 0.5.0, there was a member called ``callcode`` with similar but slightly different
+ semantics than ``delegatecall``.
+
.. index:: this, selfdestruct
@@ -204,11 +232,12 @@ Contract Related
``this`` (current contract's type):
the current contract, explicitly convertible to :ref:`address`
-``selfdestruct(address recipient)``:
+``selfdestruct(address payable recipient)``:
destroy the current contract, sending its funds to the given :ref:`address`
-``suicide(address recipient)``:
- deprecated alias to ``selfdestruct``
-
Furthermore, all functions of the current contract are callable directly including the current function.
+.. note::
+ Prior to version 0.5.0, there was a function called ``suicide`` with the same
+ semantics as ``selfdestruct``.
+
diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst
index 0a64d840..39520bec 100644
--- a/docs/using-the-compiler.rst
+++ b/docs/using-the-compiler.rst
@@ -10,13 +10,17 @@ Using the Commandline Compiler
******************************
.. note::
- This section doesn't apply to :ref:`solcjs <solcjs>`.
+ This section does not apply to :ref:`solcjs <solcjs>`, not even if it is used in commandline mode.
One of the build targets of the Solidity repository is ``solc``, the solidity commandline compiler.
Using ``solc --help`` provides you with an explanation of all options. The compiler can produce various outputs, ranging from simple binaries and assembly over an abstract syntax tree (parse tree) to estimations of gas usage.
If you only want to compile a single file, you run it as ``solc --bin sourceFile.sol`` and it will print the binary. If you want to get some of the more advanced output variants of ``solc``, it is probably better to tell it to output everything to separate files using ``solc -o outputDirectory --bin --ast --asm sourceFile.sol``.
-Before you deploy your contract, activate the optimizer while compiling using ``solc --optimize --bin sourceFile.sol``. By default, the optimizer will optimize the contract for 200 runs. If you want to optimize for initial contract deployment and get the smallest output, set it to ``--runs=1``. If you expect many transactions and don't care for higher deployment cost and output size, set ``--runs`` to a high number.
+Before you deploy your contract, activate the optimizer when compiling using ``solc --optimize --bin sourceFile.sol``.
+By default, the optimizer will optimize the contract assuming it is called 200 times across its lifetime.
+If you want the initial contract deployment to be cheaper and the later function executions to be more expensive,
+set it to ``--runs=1``. If you expect many transactions and do not care for higher deployment cost and
+output size, set ``--runs`` to a high number.
The commandline compiler will automatically read imported files from the filesystem, but
it is also possible to provide path redirects using ``prefix=path`` in the following way:
@@ -43,18 +47,78 @@ Either add ``--libraries "Math:0x12345678901234567890 Heap:0xabcdef0123456"`` to
If ``solc`` is called with the option ``--link``, all input files are interpreted to be unlinked binaries (hex-encoded) in the ``__LibraryName____``-format given above and are linked in-place (if the input is read from stdin, it is written to stdout). All options except ``--libraries`` are ignored (including ``-o``) in this case.
-If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output.
+If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses.
+
+.. _evm-version:
+.. index:: ! EVM version, compile target
+
+Setting the EVM version to target
+*********************************
+
+When you compile your contract code you can specify the Ethereum virtual machine
+version to compile for to avoid particular features or behaviours.
+
+.. warning::
+
+ Compiling for the wrong EVM version can result in wrong, strange and failing
+ behaviour. Please ensure, especially if running a private chain, that you
+ use matching EVM versions.
+
+On the command line, you can select the EVM version as follows:
+
+.. code-block:: shell
+
+ solc --evm-version <VERSION> contract.sol
+
+In the :ref:`standard JSON interface <compiler-api>`, use the ``"evmVersion"``
+key in the ``"settings"`` field:
+
+.. code-block:: none
+
+ {
+ "sources": { ... },
+ "settings": {
+ "optimizer": { ... },
+ "evmVersion": "<VERSION>"
+ }
+ }
+
+Target options
+--------------
+
+Below is a list of target EVM versions and the compiler-relevant changes introduced
+at each version. Backward compatibility is not guaranteed between each version.
+
+- ``homestead`` (oldest version)
+- ``tangerineWhistle``
+ - gas cost for access to other accounts increased, relevant for gas estimation and the optimizer.
+ - all gas sent by default for external calls, previously a certain amount had to be retained.
+- ``spuriousDragon``
+ - gas cost for the ``exp`` opcode increased, relevant for gas estimation and the optimizer.
+- ``byzantium`` (**default**)
+ - opcodes ``returndatacopy``, ``returndatasize`` and ``staticcall`` are available in assembly.
+ - the ``staticcall`` opcode is used when calling non-library view or pure functions, which prevents the functions from modifying state at the EVM level, i.e., even applies when you use invalid type conversions.
+ - it is possible to access dynamic data returned from function calls.
+ - ``revert`` opcode introduced, which means that ``revert()`` will not waste gas.
+- ``constantinople`` (still in progress)
+ - opcodes ``shl``, ``shr`` and ``sar`` are available in assembly.
+ - shifting operators use shifting opcodes and thus need less gas.
.. _compiler-api:
Compiler Input and Output JSON Description
******************************************
-These JSON formats are used by the compiler API as well as are available through ``solc``. These are subject to change,
-some fields are optional (as noted), but it is aimed at to only make backwards compatible changes.
+The recommended way to interface with the Solidity compiler especially for
+more complex and automated setups is the so-called JSON-input-output interface.
+The same interface is provided by all distributions of the compiler.
+
+The fields are generally subject to change,
+some are optional (as noted), but we try to only make backwards compatible changes.
The compiler API expects a JSON formatted input and outputs the compilation result in a JSON formatted output.
+The following subsections describe the format through an example.
Comments are of course not permitted and used here only for explanatory purposes.
Input Description
@@ -63,7 +127,7 @@ Input Description
.. code-block:: none
{
- // Required: Source code language, such as "Solidity", "serpent", "lll", "assembly", etc.
+ // Required: Source code language, such as "Solidity", "Vyper", "lll", "assembly", etc.
language: "Solidity",
// Required
sources:
diff --git a/docs/yul.rst b/docs/yul.rst
index e010a708..cfeec4db 100644
--- a/docs/yul.rst
+++ b/docs/yul.rst
@@ -83,6 +83,7 @@ Grammar::
FunctionDefinition |
VariableDeclaration |
Assignment |
+ If |
Expression |
Switch |
ForLoop |
@@ -417,6 +418,12 @@ The following functions must be available:
| create(v:u256, p:u256, s:u256) | create new contract with code mem[p..(p+s)) and send v wei |
| | and return the new address |
+---------------------------------------------+-----------------------------------------------------------------+
+| create2(v:u256, n:u256, p:u256, s:u256) | create new contract with code mem[p...(p+s)) at address |
+| | keccak256(0xff . self . n . keccak256(mem[p...(p+s))) |
+| | and send v wei and return the new address, where ``0xff`` is a |
+| | 8 byte value, ``self`` is the current contract's address |
+| | as a 20 byte value and ``n`` is a big-endian 256-bit value |
++---------------------------------------------+-----------------------------------------------------------------+
| call(g:u256, a:u256, v:u256, in:u256, | call contract at address a with input mem[in..(in+insize)) |
| insize:u256, out:u256, | providing g gas and v wei and output area |
| outsize:u256) | mem[out..(out+outsize)) returning 0 on error (eg. out of gas) |
@@ -492,6 +499,8 @@ The following functions must be available:
+---------------------------------------------+-----------------------------------------------------------------+
| extcodecopy(a:u256, t:u256, f:u256, s:u256) | like codecopy(t, f, s) but take code at address a |
+---------------------------------------------+-----------------------------------------------------------------+
+| extcodehash(a:u256) | code hash of address a |
++---------------------------------------------+-----------------------------------------------------------------+
| *Others* |
+---------------------------------------------+-----------------------------------------------------------------+
| discard(unused:bool) | discard value |
diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp
index b0e40ccb..e41a5e3b 100644
--- a/libdevcore/SHA3.cpp
+++ b/libdevcore/SHA3.cpp
@@ -67,22 +67,22 @@ deckeccak(512)
/*** Constants. ***/
static const uint8_t rho[24] = \
- { 1, 3, 6, 10, 15, 21,
+ { 1, 3, 6, 10, 15, 21,
28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43,
62, 18, 39, 61, 20, 44};
static const uint8_t pi[24] = \
- {10, 7, 11, 17, 18, 3,
+ {10, 7, 11, 17, 18, 3,
5, 16, 8, 21, 24, 4,
- 15, 23, 19, 13, 12, 2,
- 20, 14, 22, 9, 6, 1};
+ 15, 23, 19, 13, 12, 2,
+ 20, 14, 22, 9, 6, 1};
static const uint64_t RC[24] = \
- {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
- 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
- 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
- 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
- 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
- 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
+ {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
+ 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
+ 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
+ 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
+ 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
+ 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
/*** Helper macros to unroll the permutation. ***/
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
@@ -95,36 +95,37 @@ static const uint64_t RC[24] = \
/*** Keccak-f[1600] ***/
static inline void keccakf(void* state) {
- uint64_t* a = (uint64_t*)state;
- uint64_t b[5] = {0};
-
- for (int i = 0; i < 24; i++) {
- uint8_t x, y;
- // Theta
- FOR5(x, 1,
- b[x] = 0;
- FOR5(y, 5,
- b[x] ^= a[x + y]; ))
- FOR5(x, 1,
- FOR5(y, 5,
- a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
- // Rho and pi
- uint64_t t = a[1];
- x = 0;
- REPEAT24(b[0] = a[pi[x]];
- a[pi[x]] = rol(t, rho[x]);
- t = b[0];
- x++; )
- // Chi
- FOR5(y,
- 5,
- FOR5(x, 1,
- b[x] = a[y + x];)
- FOR5(x, 1,
- a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
- // Iota
- a[0] ^= RC[i];
- }
+ uint64_t* a = (uint64_t*)state;
+ uint64_t b[5] = {0};
+
+ for (int i = 0; i < 24; i++)
+ {
+ uint8_t x, y;
+ // Theta
+ FOR5(x, 1,
+ b[x] = 0;
+ FOR5(y, 5,
+ b[x] ^= a[x + y]; ))
+ FOR5(x, 1,
+ FOR5(y, 5,
+ a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
+ // Rho and pi
+ uint64_t t = a[1];
+ x = 0;
+ REPEAT24(b[0] = a[pi[x]];
+ a[pi[x]] = rol(t, rho[x]);
+ t = b[0];
+ x++; )
+ // Chi
+ FOR5(y,
+ 5,
+ FOR5(x, 1,
+ b[x] = a[y + x];)
+ FOR5(x, 1,
+ a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
+ // Iota
+ a[0] ^= RC[i];
+ }
}
/******** The FIPS202-defined functions. ********/
@@ -166,24 +167,25 @@ mkapply_sd(setout, dst[i] = src[i]) // setout
static inline int hash(uint8_t* out, size_t outlen,
const uint8_t* in, size_t inlen,
size_t rate, uint8_t delim) {
- if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
- return -1;
- }
- uint8_t a[Plen] = {0};
- // Absorb input.
- foldP(in, inlen, xorin);
- // Xor in the DS and pad frame.
- a[inlen] ^= delim;
- a[rate - 1] ^= 0x80;
- // Xor in the last block.
- xorin(a, in, inlen);
- // Apply P
- P(a);
- // Squeeze output.
- foldP(out, outlen, setout);
- setout(a, out, outlen);
- memset(a, 0, 200);
- return 0;
+ if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen))
+ {
+ return -1;
+ }
+ uint8_t a[Plen] = {0};
+ // Absorb input.
+ foldP(in, inlen, xorin);
+ // Xor in the DS and pad frame.
+ a[inlen] ^= delim;
+ a[rate - 1] ^= 0x80;
+ // Xor in the last block.
+ xorin(a, in, inlen);
+ // Apply P
+ P(a);
+ // Squeeze output.
+ foldP(out, outlen, setout);
+ setout(a, out, outlen);
+ memset(a, 0, 200);
+ return 0;
}
/*** Helper macros to define SHA3 and SHAKE instances. ***/
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index e49e675d..c2eaa1ca 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -41,10 +41,19 @@ void Assembly::append(Assembly const& _a)
auto newDeposit = m_deposit + _a.deposit();
for (AssemblyItem i: _a.m_items)
{
- if (i.type() == Tag || i.type() == PushTag)
+ switch (i.type())
+ {
+ case Tag:
+ case PushTag:
i.setData(i.data() + m_usedTags);
- else if (i.type() == PushSub || i.type() == PushSubSize)
+ break;
+ case PushSub:
+ case PushSubSize:
i.setData(i.data() + m_subs.size());
+ break;
+ default:
+ break;
+ }
append(i);
}
m_deposit = newDeposit;
@@ -69,6 +78,21 @@ void Assembly::append(Assembly const& _a, int _deposit)
append(Instruction::POP);
}
+AssemblyItem const& Assembly::append(AssemblyItem const& _i)
+{
+ assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
+ m_deposit += _i.deposit();
+ m_items.push_back(_i);
+ if (m_items.back().location().isEmpty() && !m_currentSourceLocation.isEmpty())
+ m_items.back().setLocation(m_currentSourceLocation);
+ return back();
+}
+
+void Assembly::injectStart(AssemblyItem const& _i)
+{
+ m_items.insert(m_items.begin(), _i);
+}
+
unsigned Assembly::bytesRequired(unsigned subTagSize) const
{
for (unsigned tagSize = subTagSize; true; ++tagSize)
@@ -323,16 +347,6 @@ Json::Value Assembly::assemblyJSON(StringMap const& _sourceCodes) const
return root;
}
-AssemblyItem const& Assembly::append(AssemblyItem const& _i)
-{
- assertThrow(m_deposit >= 0, AssemblyException, "Stack underflow.");
- m_deposit += _i.deposit();
- m_items.push_back(_i);
- if (m_items.back().location().isEmpty() && !m_currentSourceLocation.isEmpty())
- m_items.back().setLocation(m_currentSourceLocation);
- return back();
-}
-
AssemblyItem Assembly::namedTag(string const& _name)
{
assertThrow(!_name.empty(), AssemblyException, "Empty named tag.");
@@ -348,11 +362,6 @@ AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier)
return AssemblyItem(PushLibraryAddress, h);
}
-void Assembly::injectStart(AssemblyItem const& _i)
-{
- m_items.insert(m_items.begin(), _i);
-}
-
Assembly& Assembly::optimise(bool _enable, EVMVersion _evmVersion, bool _isCreation, size_t _runs)
{
OptimiserSettings settings;
diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h
index 1ed9b859..2a29874e 100644
--- a/libevmasm/Assembly.h
+++ b/libevmasm/Assembly.h
@@ -52,18 +52,19 @@ public:
/// Returns a tag identified by the given name. Creates it if it does not yet exist.
AssemblyItem namedTag(std::string const& _name);
AssemblyItem newData(bytes const& _data) { h256 h(dev::keccak256(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); }
+ bytes const& data(h256 const& _i) const { return m_data.at(_i); }
AssemblyItem newSub(AssemblyPointer const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); }
Assembly const& sub(size_t _sub) const { return *m_subs.at(_sub); }
Assembly& sub(size_t _sub) { return *m_subs.at(_sub); }
- AssemblyItem newPushString(std::string const& _data) { h256 h(dev::keccak256(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); }
AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); }
AssemblyItem newPushLibraryAddress(std::string const& _identifier);
- void append(Assembly const& _a);
- void append(Assembly const& _a, int _deposit);
AssemblyItem const& append(AssemblyItem const& _i);
AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); }
AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); }
+
+ template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; }
+
/// Pushes the final size of the current assembly itself. Use this when the code is modified
/// after compilation and CODESIZE is not an option.
void appendProgramSize() { append(AssemblyItem(PushProgramSize)); }
@@ -84,12 +85,9 @@ public:
/// Appends @a _data literally to the very end of the bytecode.
void appendAuxiliaryDataToEnd(bytes const& _data) { m_auxiliaryData += _data; }
- template <class T> Assembly& operator<<(T const& _d) { append(_d); return *this; }
+ /// Returns the assembly items.
AssemblyItems const& items() const { return m_items; }
- AssemblyItem const& back() const { return m_items.back(); }
- std::string backString() const { return m_items.size() && m_items.back().type() == PushString ? m_strings.at((h256)m_items.back().data()) : std::string(); }
- void injectStart(AssemblyItem const& _i);
int deposit() const { return m_deposit; }
void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assertThrow(m_deposit >= 0, InvalidDeposit, ""); }
void setDeposit(int _deposit) { m_deposit = _deposit; assertThrow(m_deposit >= 0, InvalidDeposit, ""); }
@@ -97,9 +95,8 @@ public:
/// Changes the source location used for each appended item.
void setSourceLocation(SourceLocation const& _location) { m_currentSourceLocation = _location; }
- /// Assembles the assembly into bytecode. The assembly should not be modified after this call.
+ /// Assembles the assembly into bytecode. The assembly should not be modified after this call, since the assembled version is cached.
LinkerObject const& assemble() const;
- bytes const& data(h256 const& _i) const { return m_data.at(_i); }
struct OptimiserSettings
{
@@ -140,6 +137,18 @@ public:
StringMap const& _sourceCodes = StringMap()
) const;
+public:
+ // These features are only used by LLL
+ AssemblyItem newPushString(std::string const& _data) { h256 h(dev::keccak256(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); }
+
+ void append(Assembly const& _a);
+ void append(Assembly const& _a, int _deposit);
+
+ void injectStart(AssemblyItem const& _i);
+
+ AssemblyItem const& back() const { return m_items.back(); }
+ std::string backString() const { return m_items.size() && m_items.back().type() == PushString ? m_strings.at((h256)m_items.back().data()) : std::string(); }
+
protected:
/// Does the same operations as @a optimise, but should only be applied to a sub and
/// returns the replaced tags. Also takes an argument containing the tags of this assembly
diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp
index 293cb02c..39485dd9 100644
--- a/libevmasm/CommonSubexpressionEliminator.cpp
+++ b/libevmasm/CommonSubexpressionEliminator.cpp
@@ -160,7 +160,7 @@ AssemblyItems CSECodeGenerator::generateCode(
if (seqNr < _initialSequenceNumber)
// Invalid sequenced operation.
// @todo quick fix for now. Proper fix needs to choose representative with higher
- // sequence number during dependency analyis.
+ // sequence number during dependency analysis.
BOOST_THROW_EXCEPTION(StackTooDeepException());
sequencedExpressions.insert(make_pair(seqNr, id));
}
diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp
index 07ece12c..9844ba3a 100644
--- a/libevmasm/ConstantOptimiser.cpp
+++ b/libevmasm/ConstantOptimiser.cpp
@@ -94,15 +94,7 @@ bigint ConstantOptimisationMethod::simpleRunGas(AssemblyItems const& _items)
bigint ConstantOptimisationMethod::dataGas(bytes const& _data) const
{
assertThrow(_data.size() > 0, OptimizerException, "Empty bytecode generated.");
- if (m_params.isCreation)
- {
- bigint gas;
- for (auto b: _data)
- gas += b ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas;
- return gas;
- }
- else
- return GasCosts::createDataGas * _data.size();
+ return bigint(GasMeter::dataGas(_data, m_params.isCreation));
}
size_t ConstantOptimisationMethod::bytesRequired(AssemblyItems const& _items)
diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp
index 69b33ec5..42a1819a 100644
--- a/libevmasm/ExpressionClasses.cpp
+++ b/libevmasm/ExpressionClasses.cpp
@@ -184,6 +184,7 @@ string ExpressionClasses::fullDAGToString(ExpressionClasses::Id _id) const
ExpressionClasses::Id ExpressionClasses::tryToSimplify(Expression const& _expr)
{
static Rules rules;
+ assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized.");
if (
!_expr.item ||
diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp
index caa06fc0..d98b3efa 100644
--- a/libevmasm/GasMeter.cpp
+++ b/libevmasm/GasMeter.cpp
@@ -101,8 +101,8 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
break;
case Instruction::KECCAK256:
gas = GasCosts::keccak256Gas;
- gas += wordGas(GasCosts::keccak256WordGas, m_state->relativeStackElement(-1));
gas += memoryGas(0, -1);
+ gas += wordGas(GasCosts::keccak256WordGas, m_state->relativeStackElement(-1));
break;
case Instruction::CALLDATACOPY:
case Instruction::CODECOPY:
@@ -114,6 +114,9 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
case Instruction::EXTCODESIZE:
gas = GasCosts::extCodeGas(m_evmVersion);
break;
+ case Instruction::EXTCODEHASH:
+ gas = GasCosts::balanceGas(m_evmVersion);
+ break;
case Instruction::EXTCODECOPY:
gas = GasCosts::extCodeGas(m_evmVersion);
gas += memoryGas(-1, -3);
@@ -125,8 +128,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _
case Instruction::LOG3:
case Instruction::LOG4:
{
- unsigned n = unsigned(_item.instruction()) - unsigned(Instruction::LOG0);
- gas = GasCosts::logGas + GasCosts::logTopicGas * n;
+ gas = GasCosts::logGas + GasCosts::logTopicGas * getLogNumber(_item.instruction());
gas += memoryGas(0, -1);
if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1)))
gas += GasCosts::logDataGas * (*value);
@@ -215,7 +217,7 @@ GasMeter::GasConsumption GasMeter::memoryGas(ExpressionClasses::Id _position)
if (!value)
return GasConsumption::infinite();
if (*value < m_largestMemoryAccess)
- return GasConsumption(u256(0));
+ return GasConsumption(0);
u256 previous = m_largestMemoryAccess;
m_largestMemoryAccess = *value;
auto memGas = [=](u256 const& pos) -> u256
@@ -258,4 +260,16 @@ unsigned GasMeter::runGas(Instruction _instruction)
return 0;
}
-
+u256 GasMeter::dataGas(bytes const& _data, bool _inCreation)
+{
+ bigint gas = 0;
+ if (_inCreation)
+ {
+ for (auto b: _data)
+ gas += (b != 0) ? GasCosts::txDataNonZeroGas : GasCosts::txDataZeroGas;
+ }
+ else
+ gas = bigint(GasCosts::createDataGas) * _data.size();
+ assertThrow(gas < bigint(u256(-1)), OptimizerException, "Gas cost exceeds 256 bits.");
+ return u256(gas);
+}
diff --git a/libevmasm/GasMeter.h b/libevmasm/GasMeter.h
index fc3740d2..da90b028 100644
--- a/libevmasm/GasMeter.h
+++ b/libevmasm/GasMeter.h
@@ -136,6 +136,11 @@ public:
/// change with EVM versions)
static unsigned runGas(Instruction _instruction);
+ /// @returns the gas cost of the supplied data, depending whether it is in creation code, or not.
+ /// In case of @a _inCreation, the data is only sent as a transaction and is not stored, whereas
+ /// otherwise code will be stored and have to pay "createDataGas" cost.
+ static u256 dataGas(bytes const& _data, bool _inCreation);
+
private:
/// @returns _multiplier * (_value + 31) / 32, if _value is a known constant and infinite otherwise.
GasConsumption wordGas(u256 const& _multiplier, ExpressionClasses::Id _value);
diff --git a/libevmasm/Instruction.cpp b/libevmasm/Instruction.cpp
index d5b82e75..cf98c938 100644
--- a/libevmasm/Instruction.cpp
+++ b/libevmasm/Instruction.cpp
@@ -73,6 +73,7 @@ const std::map<std::string, Instruction> dev::solidity::c_instructions =
{ "EXTCODECOPY", Instruction::EXTCODECOPY },
{ "RETURNDATASIZE", Instruction::RETURNDATASIZE },
{ "RETURNDATACOPY", Instruction::RETURNDATACOPY },
+ { "EXTCODEHASH", Instruction::EXTCODEHASH },
{ "BLOCKHASH", Instruction::BLOCKHASH },
{ "COINBASE", Instruction::COINBASE },
{ "TIMESTAMP", Instruction::TIMESTAMP },
@@ -216,6 +217,7 @@ static const std::map<Instruction, InstructionInfo> c_instructionInfo =
{ Instruction::EXTCODECOPY, { "EXTCODECOPY", 0, 4, 0, true, Tier::ExtCode } },
{ Instruction::RETURNDATASIZE, {"RETURNDATASIZE", 0, 0, 1, false, Tier::Base } },
{ Instruction::RETURNDATACOPY, {"RETURNDATACOPY", 0, 3, 0, true, Tier::VeryLow } },
+ { Instruction::EXTCODEHASH, { "EXTCODEHASH", 0, 1, 1, false, Tier::Balance } },
{ Instruction::BLOCKHASH, { "BLOCKHASH", 0, 1, 1, false, Tier::Ext } },
{ Instruction::COINBASE, { "COINBASE", 0, 0, 1, false, Tier::Base } },
{ Instruction::TIMESTAMP, { "TIMESTAMP", 0, 0, 1, false, Tier::Base } },
diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h
index dc116f88..63424eeb 100644
--- a/libevmasm/Instruction.h
+++ b/libevmasm/Instruction.h
@@ -82,6 +82,7 @@ enum class Instruction: uint8_t
EXTCODECOPY, ///< copy external code (from another contract)
RETURNDATASIZE = 0x3d, ///< get size of return data buffer
RETURNDATACOPY = 0x3e, ///< copy return data in current environment to memory
+ EXTCODEHASH = 0x3f, ///< get external code hash (from another contract)
BLOCKHASH = 0x40, ///< get hash of most recent complete block
COINBASE, ///< get the block's coinbase address
@@ -192,8 +193,8 @@ enum class Instruction: uint8_t
CALLCODE, ///< message-call with another account's code only
RETURN, ///< halt execution returning output data
DELEGATECALL, ///< like CALLCODE but keeps caller's value and sender
+ CREATE2 = 0xf5, ///< create new account with associated code at address `sha3(0xff + sender + salt + init code) % 2**160`
STATICCALL = 0xfa, ///< like CALL but disallow state modifications
- CREATE2 = 0xfb, ///< create new account with associated code at address `sha3(sender + salt + sha3(init code)) % 2**160`
REVERT = 0xfd, ///< halt execution, revert state and return output data
INVALID = 0xfe, ///< invalid instruction for expressing runtime errors (e.g., division-by-zero)
@@ -218,6 +219,12 @@ inline bool isSwapInstruction(Instruction _inst)
return Instruction::SWAP1 <= _inst && _inst <= Instruction::SWAP16;
}
+/// @returns true if the instruction is a LOG
+inline bool isLogInstruction(Instruction _inst)
+{
+ return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4;
+}
+
/// @returns the number of PUSH Instruction _inst
inline unsigned getPushNumber(Instruction _inst)
{
@@ -236,6 +243,12 @@ inline unsigned getSwapNumber(Instruction _inst)
return (byte)_inst - unsigned(Instruction::SWAP1) + 1;
}
+/// @returns the number of LOG Instruction _inst
+inline unsigned getLogNumber(Instruction _inst)
+{
+ return (byte)_inst - unsigned(Instruction::LOG0);
+}
+
/// @returns the PUSH<_number> instruction
inline Instruction pushInstruction(unsigned _number)
{
diff --git a/libevmasm/PathGasMeter.h b/libevmasm/PathGasMeter.h
index 9537b176..fb821684 100644
--- a/libevmasm/PathGasMeter.h
+++ b/libevmasm/PathGasMeter.h
@@ -57,6 +57,16 @@ public:
GasMeter::GasConsumption estimateMax(size_t _startIndex, std::shared_ptr<KnownState> const& _state);
+ static GasMeter::GasConsumption estimateMax(
+ AssemblyItems const& _items,
+ solidity::EVMVersion _evmVersion,
+ size_t _startIndex,
+ std::shared_ptr<KnownState> const& _state
+ )
+ {
+ return PathGasMeter(_items, _evmVersion).estimateMax(_startIndex, _state);
+ }
+
private:
/// Adds a new path item to the queue, but only if we do not already have
/// a higher gas usage at that point.
diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h
index 0573856b..874a8929 100644
--- a/libevmasm/RuleList.h
+++ b/libevmasm/RuleList.h
@@ -44,12 +44,11 @@ template <class S> S modWorkaround(S const& _a, S const& _b)
return (S)(bigint(_a) % bigint(_b));
}
-/// @returns a list of simplification rules given certain match placeholders.
-/// A, B and C should represent constants, X and Y arbitrary expressions.
-/// The simplifications should never change the order of evaluation of
-/// arbitrary operations.
+// This part of simplificationRuleList below was split out to prevent
+// stack overflows in the JavaScript optimizer for emscripten builds
+// that affected certain browser versions.
template <class Pattern>
-std::vector<SimplificationRule<Pattern>> simplificationRuleList(
+std::vector<SimplificationRule<Pattern>> simplificationRuleListPart1(
Pattern A,
Pattern B,
Pattern C,
@@ -57,8 +56,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
Pattern Y
)
{
- std::vector<SimplificationRule<Pattern>> rules;
- rules += std::vector<SimplificationRule<Pattern>>{
+ return std::vector<SimplificationRule<Pattern>> {
// arithmetic on constants
{{Instruction::ADD, {A, B}}, [=]{ return A.d() + B.d(); }, false},
{{Instruction::MUL, {A, B}}, [=]{ return A.d() * B.d(); }, false},
@@ -162,6 +160,22 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
{{Instruction::OR, {X, {Instruction::NOT, {X}}}}, [=]{ return ~u256(0); }, true},
{{Instruction::OR, {{Instruction::NOT, {X}}, X}}, [=]{ return ~u256(0); }, true},
};
+}
+
+
+// This part of simplificationRuleList below was split out to prevent
+// stack overflows in the JavaScript optimizer for emscripten builds
+// that affected certain browser versions.
+template <class Pattern>
+std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2(
+ Pattern A,
+ Pattern B,
+ Pattern,
+ Pattern X,
+ Pattern Y
+)
+{
+ std::vector<SimplificationRule<Pattern>> rules;
// Replace MOD X, <power-of-two> with AND X, <power-of-two> - 1
for (size_t i = 0; i < 256; ++i)
@@ -292,5 +306,24 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
return rules;
}
+/// @returns a list of simplification rules given certain match placeholders.
+/// A, B and C should represent constants, X and Y arbitrary expressions.
+/// The simplifications should never change the order of evaluation of
+/// arbitrary operations.
+template <class Pattern>
+std::vector<SimplificationRule<Pattern>> simplificationRuleList(
+ Pattern A,
+ Pattern B,
+ Pattern C,
+ Pattern X,
+ Pattern Y
+)
+{
+ std::vector<SimplificationRule<Pattern>> rules;
+ rules += simplificationRuleListPart1(A, B, C, X, Y);
+ rules += simplificationRuleListPart2(A, B, C, X, Y);
+ return rules;
+}
+
}
}
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp
index 71267ee8..78f3c9c7 100644
--- a/libevmasm/SemanticInformation.cpp
+++ b/libevmasm/SemanticInformation.cpp
@@ -151,6 +151,7 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
case Instruction::MSIZE: // depends on previous writes and reads, not only on content
case Instruction::BALANCE: // depends on previous calls
case Instruction::EXTCODESIZE:
+ case Instruction::EXTCODEHASH:
case Instruction::RETURNDATACOPY: // depends on previous calls
case Instruction::RETURNDATASIZE:
return false;
@@ -172,6 +173,7 @@ bool SemanticInformation::movable(Instruction _instruction)
case Instruction::KECCAK256:
case Instruction::BALANCE:
case Instruction::EXTCODESIZE:
+ case Instruction::EXTCODEHASH:
case Instruction::RETURNDATASIZE:
case Instruction::SLOAD:
case Instruction::PC:
@@ -233,6 +235,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
case Instruction::GASPRICE:
case Instruction::EXTCODESIZE:
case Instruction::EXTCODECOPY:
+ case Instruction::EXTCODEHASH:
case Instruction::BLOCKHASH:
case Instruction::COINBASE:
case Instruction::TIMESTAMP:
diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp
index 504dbc24..ba13a611 100644
--- a/libevmasm/SimplificationRules.cpp
+++ b/libevmasm/SimplificationRules.cpp
@@ -21,16 +21,19 @@
* Container for equivalence classes of expressions for use in common subexpression elimination.
*/
+#include <libevmasm/SimplificationRules.h>
+
#include <libevmasm/ExpressionClasses.h>
-#include <utility>
-#include <functional>
-#include <boost/range/adaptor/reversed.hpp>
-#include <boost/noncopyable.hpp>
#include <libevmasm/Assembly.h>
#include <libevmasm/CommonSubexpressionEliminator.h>
-#include <libevmasm/SimplificationRules.h>
-
#include <libevmasm/RuleList.h>
+#include <libdevcore/Assertions.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <utility>
+#include <functional>
using namespace std;
using namespace dev;
@@ -54,6 +57,11 @@ SimplificationRule<Pattern> const* Rules::findFirstMatch(
return nullptr;
}
+bool Rules::isInitialized() const
+{
+ return !m_rules[byte(Instruction::ADD)].empty();
+}
+
void Rules::addRules(std::vector<SimplificationRule<Pattern>> const& _rules)
{
for (auto const& r: _rules)
@@ -82,6 +90,7 @@ Rules::Rules()
Y.setMatchGroup(5, m_matchGroups);
addRules(simplificationRuleList(A, B, C, X, Y));
+ assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
}
Pattern::Pattern(Instruction _instruction, std::vector<Pattern> const& _arguments):
diff --git a/libevmasm/SimplificationRules.h b/libevmasm/SimplificationRules.h
index 53f7e595..fbe5a2b0 100644
--- a/libevmasm/SimplificationRules.h
+++ b/libevmasm/SimplificationRules.h
@@ -26,6 +26,8 @@
#include <libevmasm/ExpressionClasses.h>
#include <libevmasm/SimplificationRule.h>
+#include <boost/noncopyable.hpp>
+
#include <functional>
#include <vector>
@@ -53,6 +55,10 @@ public:
ExpressionClasses const& _classes
);
+ /// Checks whether the rulelist is non-empty. This is usually enforced
+ /// by the constructor, but we had some issues with static initialization.
+ bool isInitialized() const;
+
private:
void addRules(std::vector<SimplificationRule<Pattern>> const& _rules);
void addRule(SimplificationRule<Pattern> const& _rule);
diff --git a/libjulia/backends/evm/AbstractAssembly.h b/libjulia/backends/evm/AbstractAssembly.h
index 6b1b5c23..b6818923 100644
--- a/libjulia/backends/evm/AbstractAssembly.h
+++ b/libjulia/backends/evm/AbstractAssembly.h
@@ -103,7 +103,7 @@ enum class IdentifierContext { LValue, RValue };
struct ExternalIdentifierAccess
{
using Resolver = std::function<size_t(solidity::assembly::Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
- /// Resolve a an external reference given by the identifier in the given context.
+ /// Resolve an external reference given by the identifier in the given context.
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
Resolver resolve;
using CodeGenerator = std::function<void(solidity::assembly::Identifier const&, IdentifierContext, julia::AbstractAssembly&)>;
diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp
index f4e49655..dc536f77 100644
--- a/libjulia/backends/evm/EVMCodeTransform.cpp
+++ b/libjulia/backends/evm/EVMCodeTransform.cpp
@@ -545,11 +545,13 @@ void CodeTransform::expectDeposit(int _deposit, int _oldHeight) const
void CodeTransform::checkStackHeight(void const* _astElement) const
{
solAssert(m_info.stackHeightInfo.count(_astElement), "Stack height for AST element not found.");
+ int stackHeightInAnalysis = m_info.stackHeightInfo.at(_astElement);
+ int stackHeightInCodegen = m_assembly.stackHeight() - m_stackAdjustment;
solAssert(
- m_info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_stackAdjustment,
+ stackHeightInAnalysis == stackHeightInCodegen,
"Stack height mismatch between analysis and code generation phase: Analysis: " +
- to_string(m_info.stackHeightInfo.at(_astElement)) +
+ to_string(stackHeightInAnalysis) +
" code gen: " +
- to_string(m_assembly.stackHeight() - m_stackAdjustment)
+ to_string(stackHeightInCodegen)
);
}
diff --git a/libjulia/optimiser/FullInliner.cpp b/libjulia/optimiser/FullInliner.cpp
index e8776e23..f41dc198 100644
--- a/libjulia/optimiser/FullInliner.cpp
+++ b/libjulia/optimiser/FullInliner.cpp
@@ -89,6 +89,9 @@ void InlineModifier::operator()(ForLoop& _loop)
void InlineModifier::operator()(Block& _block)
{
+ vector<Statement> saved;
+ saved.swap(m_statementsToPrefix);
+
// This is only used if needed to minimize the number of move operations.
vector<Statement> modifiedStatements;
for (size_t i = 0; i < _block.statements.size(); ++i)
@@ -110,6 +113,8 @@ void InlineModifier::operator()(Block& _block)
}
if (!modifiedStatements.empty())
_block.statements = std::move(modifiedStatements);
+
+ saved.swap(m_statementsToPrefix);
}
void InlineModifier::visit(Expression& _expression)
diff --git a/libjulia/optimiser/SimplificationRules.cpp b/libjulia/optimiser/SimplificationRules.cpp
index a5e296c3..56cb96ac 100644
--- a/libjulia/optimiser/SimplificationRules.cpp
+++ b/libjulia/optimiser/SimplificationRules.cpp
@@ -40,6 +40,7 @@ SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(Expressio
return nullptr;
static SimplificationRules rules;
+ assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized.");
FunctionalInstruction const& instruction = boost::get<FunctionalInstruction>(_expr);
for (auto const& rule: rules.m_rules[byte(instruction.instruction)])
@@ -51,6 +52,11 @@ SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(Expressio
return nullptr;
}
+bool SimplificationRules::isInitialized() const
+{
+ return !m_rules[byte(solidity::Instruction::ADD)].empty();
+}
+
void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules)
{
for (auto const& r: _rules)
@@ -79,6 +85,7 @@ SimplificationRules::SimplificationRules()
Y.setMatchGroup(5, m_matchGroups);
addRules(simplificationRuleList(A, B, C, X, Y));
+ assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
}
Pattern::Pattern(solidity::Instruction _instruction, vector<Pattern> const& _arguments):
diff --git a/libjulia/optimiser/SimplificationRules.h b/libjulia/optimiser/SimplificationRules.h
index 68b640b1..e35e6466 100644
--- a/libjulia/optimiser/SimplificationRules.h
+++ b/libjulia/optimiser/SimplificationRules.h
@@ -51,6 +51,9 @@ public:
/// groups accordingly.
static SimplificationRule<Pattern> const* findFirstMatch(Expression const& _expr);
+ /// Checks whether the rulelist is non-empty. This is usually enforced
+ /// by the constructor, but we had some issues with static initialization.
+ bool isInitialized() const;
private:
void addRules(std::vector<SimplificationRule<Pattern>> const& _rules);
void addRule(SimplificationRule<Pattern> const& _rule);
diff --git a/liblll/Compiler.cpp b/liblll/Compiler.cpp
index 657f58b8..f944adbd 100644
--- a/liblll/Compiler.cpp
+++ b/liblll/Compiler.cpp
@@ -90,7 +90,8 @@ std::string dev::lll::compileLLLToAsm(std::string const& _src, EVMVersion _evmVe
}
catch (std::exception const& _e)
{
- if (_errors) {
+ if (_errors)
+ {
_errors->push_back("Parse exception.");
_errors->push_back(boost::diagnostic_information(_e));
}
diff --git a/liblll/Parser.cpp b/liblll/Parser.cpp
index c3c33306..854aeecc 100644
--- a/liblll/Parser.cpp
+++ b/liblll/Parser.cpp
@@ -148,7 +148,8 @@ void dev::lll::parseTreeLLL(string const& _s, sp::utree& o_out)
BOOST_THROW_EXCEPTION(ParserException() << errinfo_comment(reason));
}
for (auto i = ret; i != s.cend(); ++i)
- if (!isspace(*i)) {
+ if (!isspace(*i))
+ {
BOOST_THROW_EXCEPTION(ParserException() << errinfo_comment("Non-whitespace left in parser"));
}
}
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index 3ac8fd47..cba2655c 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.cpp
@@ -56,10 +56,10 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
+ make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
- make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)),
+ make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction))
})
{
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 8750b47b..81de3c43 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -112,7 +112,28 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
{
- _typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
+ if (!_typeName.annotation().type)
+ {
+ _typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
+ if (_typeName.stateMutability().is_initialized())
+ {
+ // for non-address types this was already caught by the parser
+ solAssert(_typeName.annotation().type->category() == Type::Category::Address, "");
+ switch(*_typeName.stateMutability())
+ {
+ case StateMutability::Payable:
+ case StateMutability::NonPayable:
+ _typeName.annotation().type = make_shared<AddressType>(*_typeName.stateMutability());
+ break;
+ default:
+ m_errorReporter.typeError(
+ _typeName.location(),
+ "Address types can only be payable or non-payable."
+ );
+ break;
+ }
+ }
+ }
return true;
}
@@ -225,6 +246,8 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric.get());
if (!lengthType || !lengthType->mobileType())
fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression.");
+ else if (lengthType->isZero())
+ fatalTypeError(length->location(), "Array with zero length specified.");
else if (lengthType->isFractional())
fatalTypeError(length->location(), "Array with fractional length specified.");
else if (lengthType->isNegative())
diff --git a/libsolidity/analysis/SemVerHandler.cpp b/libsolidity/analysis/SemVerHandler.cpp
index 42186396..29f6d5de 100644
--- a/libsolidity/analysis/SemVerHandler.cpp
+++ b/libsolidity/analysis/SemVerHandler.cpp
@@ -106,18 +106,22 @@ bool SemVerMatchExpression::MatchComponent::matches(SemVerVersion const& _versio
}
if (cmp == 0 && !_version.prerelease.empty() && didCompare)
cmp = -1;
- if (prefix == Token::Assign)
+
+ switch (prefix)
+ {
+ case Token::Assign:
return cmp == 0;
- else if (prefix == Token::LessThan)
+ case Token::LessThan:
return cmp < 0;
- else if (prefix == Token::LessThanOrEqual)
+ case Token::LessThanOrEqual:
return cmp <= 0;
- else if (prefix == Token::GreaterThan)
+ case Token::GreaterThan:
return cmp > 0;
- else if (prefix == Token::GreaterThanOrEqual)
+ case Token::GreaterThanOrEqual:
return cmp >= 0;
- else
+ default:
solAssert(false, "Invalid SemVer expression");
+ }
return false;
}
}
@@ -196,21 +200,22 @@ SemVerMatchExpression::MatchComponent SemVerMatchExpressionParser::parseMatchCom
{
SemVerMatchExpression::MatchComponent component;
Token::Value token = currentToken();
- if (
- token == Token::BitXor ||
- token == Token::BitNot ||
- token == Token::LessThan ||
- token == Token::LessThanOrEqual||
- token == Token::GreaterThan ||
- token == Token::GreaterThanOrEqual ||
- token == Token::Assign
- )
+
+ switch (token)
{
+ case Token::BitXor:
+ case Token::BitNot:
+ case Token::LessThan:
+ case Token::LessThanOrEqual:
+ case Token::GreaterThan:
+ case Token::GreaterThanOrEqual:
+ case Token::Assign:
component.prefix = token;
nextToken();
- }
- else
+ break;
+ default:
component.prefix = Token::Assign;
+ }
component.levelsPresent = 0;
while (component.levelsPresent < 3)
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 143ac109..bc040623 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -535,7 +535,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
toString(arguments.size()) +
" were provided."
);
- if (arguments.size() >= 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType(DataLocation::Memory)))
+ if (arguments.size() >= 1 && !type(*arguments.front())->isImplicitlyConvertibleTo(ArrayType::bytesMemory()))
m_errorReporter.typeError(
arguments.front()->location(),
"Invalid type for argument in function call. "
@@ -571,6 +571,9 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
// data locations. Furthermore, storage can be a little dangerous and
// calldata is not really implemented anyway.
actualType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, actualType);
+ // We force address payable for address types.
+ if (actualType->category() == Type::Category::Address)
+ actualType = make_shared<AddressType>(StateMutability::Payable);
solAssert(
!actualType->dataStoredIn(DataLocation::CallData) &&
!actualType->dataStoredIn(DataLocation::Storage),
@@ -1730,16 +1733,54 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
DataLocation dataLoc = DataLocation::Memory;
if (auto argRefType = dynamic_cast<ReferenceType const*>(argType.get()))
dataLoc = argRefType->location();
- resultType = ReferenceType::copyForLocationIfReference(dataLoc, resultType);
- if (!argType->isExplicitlyConvertibleTo(*resultType))
- m_errorReporter.typeError(
- _functionCall.location(),
- "Explicit type conversion not allowed from \"" +
- argType->toString() +
- "\" to \"" +
- resultType->toString() +
- "\"."
- );
+ if (auto type = dynamic_cast<ReferenceType const*>(resultType.get()))
+ resultType = type->copyForLocation(dataLoc, type->isPointer());
+ if (argType->isExplicitlyConvertibleTo(*resultType))
+ {
+ if (auto argArrayType = dynamic_cast<ArrayType const*>(argType.get()))
+ {
+ auto resultArrayType = dynamic_cast<ArrayType const*>(resultType.get());
+ solAssert(!!resultArrayType, "");
+ solAssert(
+ argArrayType->location() != DataLocation::Storage ||
+ ((resultArrayType->isPointer() || (argArrayType->isByteArray() && resultArrayType->isByteArray())) &&
+ resultArrayType->location() == DataLocation::Storage),
+ "Invalid explicit conversion to storage type."
+ );
+ }
+ }
+ else
+ {
+ if (resultType->category() == Type::Category::Contract && argType->category() == Type::Category::Address)
+ {
+ solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), "");
+ solAssert(dynamic_cast<AddressType const*>(argType.get())->stateMutability() < StateMutability::Payable, "");
+ SecondarySourceLocation ssl;
+ if (auto const* identifier = dynamic_cast<Identifier const*>(arguments.front().get()))
+ if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration))
+ ssl.append("Did you mean to declare this variable as \"address payable\"?", variableDeclaration->location());
+ m_errorReporter.typeError(
+ _functionCall.location(), ssl,
+ "Explicit type conversion not allowed from non-payable \"address\" to \"" +
+ resultType->toString() +
+ "\", which has a payable fallback function."
+ );
+ }
+ else
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Explicit type conversion not allowed from \"" +
+ argType->toString() +
+ "\" to \"" +
+ resultType->toString() +
+ "\"."
+ );
+ }
+ if (resultType->category() == Type::Category::Address)
+ {
+ bool payable = argType->isExplicitlyConvertibleTo(AddressType::addressPayable());
+ resultType = make_shared<AddressType>(payable ? StateMutability::Payable : StateMutability::NonPayable);
+ }
}
_functionCall.annotation().type = resultType;
_functionCall.annotation().isPure = isPure;
@@ -1998,7 +2039,7 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
if (!contract)
m_errorReporter.fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
if (contract->contractKind() == ContractDefinition::ContractKind::Interface)
- m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface.");
+ m_errorReporter.fatalTypeError(_newExpression.location(), "Cannot instantiate an interface.");
if (!contract->annotation().unimplementedFunctions.empty())
{
SecondarySourceLocation ssl;
@@ -2103,7 +2144,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
"after argument-dependent lookup in " + exprType->toString() +
(memberName == "value" ? " - did you forget the \"payable\" modifier?" : ".");
if (exprType->category() == Type::Category::Contract)
- for (auto const& addressMember: AddressType().nativeMembers(nullptr))
+ for (auto const& addressMember: AddressType::addressPayable().nativeMembers(nullptr))
if (addressMember.name == memberName)
{
Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
@@ -2354,14 +2395,14 @@ void TypeChecker::endVisit(Literal const& _literal)
if (_literal.looksLikeAddress())
{
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses
- _literal.annotation().type = make_shared<AddressType>();
+ _literal.annotation().type = make_shared<AddressType>(StateMutability::Payable);
string msg;
- if (_literal.value().length() != 42) // "0x" + 40 hex digits
+ if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
// looksLikeAddress enforces that it is a hex literal starting with "0x"
msg =
"This looks like an address but is not exactly 40 hex digits. It is " +
- to_string(_literal.value().length() - 2) +
+ to_string(_literal.valueWithoutUnderscores().length() - 2) +
" hex digits.";
else if (!_literal.passesAddressChecksum())
{
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index 113a3177..b0cacc43 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -292,11 +292,11 @@ void ViewPureChecker::endVisit(FunctionCall const& _functionCall)
if (_functionCall.annotation().kind != FunctionCallKind::FunctionCall)
return;
- StateMutability mut = dynamic_cast<FunctionType const&>(*_functionCall.expression().annotation().type).stateMutability();
+ StateMutability mutability = dynamic_cast<FunctionType const&>(*_functionCall.expression().annotation().type).stateMutability();
// We only require "nonpayable" to call a payble function.
- if (mut == StateMutability::Payable)
- mut = StateMutability::NonPayable;
- reportMutability(mut, _functionCall.location());
+ if (mutability == StateMutability::Payable)
+ mutability = StateMutability::NonPayable;
+ reportMutability(mutability, _functionCall.location());
}
bool ViewPureChecker::visit(MemberAccess const& _memberAccess)
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index 8e7a81a6..d9264230 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -311,8 +311,6 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
return make_shared<FunctionType>(*this, _internal);
case Declaration::Visibility::External:
return {};
- default:
- solAssert(false, "visibility() should return a Visibility");
}
}
else
@@ -327,8 +325,6 @@ FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
case Declaration::Visibility::Public:
case Declaration::Visibility::External:
return make_shared<FunctionType>(*this, _internal);
- default:
- solAssert(false, "visibility() should return a Visibility");
}
}
@@ -568,8 +564,6 @@ FunctionTypePointer VariableDeclaration::functionType(bool _internal) const
case Declaration::Visibility::Public:
case Declaration::Visibility::External:
return make_shared<FunctionType>(*this);
- default:
- solAssert(false, "visibility() should not return a Visibility");
}
// To make the compiler happy
@@ -639,6 +633,11 @@ IdentifierAnnotation& Identifier::annotation() const
return dynamic_cast<IdentifierAnnotation&>(*m_annotation);
}
+ASTString Literal::valueWithoutUnderscores() const
+{
+ return boost::erase_all_copy(value(), "_");
+}
+
bool Literal::isHexNumber() const
{
if (token() != Token::Number)
@@ -654,20 +653,20 @@ bool Literal::looksLikeAddress() const
if (!isHexNumber())
return false;
- return abs(int(value().length()) - 42) <= 1;
+ return abs(int(valueWithoutUnderscores().length()) - 42) <= 1;
}
bool Literal::passesAddressChecksum() const
{
solAssert(isHexNumber(), "Expected hex number");
- return dev::passesAddressChecksum(value(), true);
+ return dev::passesAddressChecksum(valueWithoutUnderscores(), true);
}
string Literal::getChecksummedAddress() const
{
solAssert(isHexNumber(), "Expected hex number");
/// Pad literal to be a proper hex address.
- string address = value().substr(2);
+ string address = valueWithoutUnderscores().substr(2);
if (address.length() > 40)
return string();
address.insert(address.begin(), 40 - address.size(), '0');
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index a5cd277d..b84f9730 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -876,23 +876,31 @@ public:
};
/**
- * Any pre-defined type name represented by a single keyword, i.e. it excludes mappings,
- * contracts, functions, etc.
+ * Any pre-defined type name represented by a single keyword (and possibly a state mutability for address types),
+ * i.e. it excludes mappings, contracts, functions, etc.
*/
class ElementaryTypeName: public TypeName
{
public:
- ElementaryTypeName(SourceLocation const& _location, ElementaryTypeNameToken const& _elem):
- TypeName(_location), m_type(_elem)
- {}
+ ElementaryTypeName(
+ SourceLocation const& _location,
+ ElementaryTypeNameToken const& _elem,
+ boost::optional<StateMutability> _stateMutability = {}
+ ): TypeName(_location), m_type(_elem), m_stateMutability(_stateMutability)
+ {
+ solAssert(!_stateMutability.is_initialized() || _elem.token() == Token::Address, "");
+ }
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
ElementaryTypeNameToken const& typeName() const { return m_type; }
+ boost::optional<StateMutability> const& stateMutability() const { return m_stateMutability; }
+
private:
ElementaryTypeNameToken m_type;
+ boost::optional<StateMutability> m_stateMutability; ///< state mutability for address type
};
/**
@@ -1671,6 +1679,8 @@ public:
/// @returns the non-parsed value of the literal
ASTString const& value() const { return *m_value; }
+ ASTString valueWithoutUnderscores() const;
+
SubDenomination subDenomination() const { return m_subDenomination; }
/// @returns true if this is a number with a hex prefix.
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 5189414c..4b282d85 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -396,10 +396,15 @@ bool ASTJsonConverter::visit(EventDefinition const& _node)
bool ASTJsonConverter::visit(ElementaryTypeName const& _node)
{
- setJsonNode(_node, "ElementaryTypeName", {
+ std::vector<pair<string, Json::Value>> attributes = {
make_pair("name", _node.typeName().toString()),
make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
- });
+ };
+
+ if (_node.stateMutability())
+ attributes.emplace_back(make_pair("stateMutability", stateMutabilityToString(*_node.stateMutability())));
+
+ setJsonNode(_node, "ElementaryTypeName", std::move(attributes));
return false;
}
@@ -749,9 +754,9 @@ string ASTJsonConverter::location(VariableDeclaration::Location _location)
return "memory";
case VariableDeclaration::Location::CallData:
return "calldata";
- default:
- solAssert(false, "Unknown declaration location.");
}
+ // To make the compiler happy
+ return {};
}
string ASTJsonConverter::contractKind(ContractDefinition::ContractKind _kind)
@@ -764,9 +769,10 @@ string ASTJsonConverter::contractKind(ContractDefinition::ContractKind _kind)
return "contract";
case ContractDefinition::ContractKind::Library:
return "library";
- default:
- solAssert(false, "Unknown kind of contract.");
}
+
+ // To make the compiler happy
+ return {};
}
string ASTJsonConverter::functionCallKind(FunctionCallKind _kind)
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index a302203b..e45fc81d 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -299,7 +299,7 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
case Token::Byte:
return make_shared<FixedBytesType>(1);
case Token::Address:
- return make_shared<AddressType>();
+ return make_shared<AddressType>(StateMutability::NonPayable);
case Token::Bool:
return make_shared<BoolType>();
case Token::Bytes:
@@ -340,6 +340,17 @@ TypePointer Type::fromElementaryTypeName(string const& _name)
}
return ref->copyForLocation(location, true);
}
+ else if (t->category() == Type::Category::Address)
+ {
+ if (nameParts.size() == 2)
+ {
+ if (nameParts[1] == "payable")
+ return make_shared<AddressType>(StateMutability::Payable);
+ else
+ solAssert(false, "Invalid state mutability for address type: " + nameParts[1]);
+ }
+ return make_shared<AddressType>(StateMutability::NonPayable);
+ }
else
{
solAssert(nameParts.size() == 1, "Storage location suffix only allowed for reference types");
@@ -439,21 +450,48 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
return members;
}
+AddressType::AddressType(StateMutability _stateMutability):
+ m_stateMutability(_stateMutability)
+{
+ solAssert(m_stateMutability == StateMutability::Payable || m_stateMutability == StateMutability::NonPayable, "");
+}
+
string AddressType::richIdentifier() const
{
- return "t_address";
+ if (m_stateMutability == StateMutability::Payable)
+ return "t_address_payable";
+ else
+ return "t_address";
+}
+
+bool AddressType::isImplicitlyConvertibleTo(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ AddressType const& other = dynamic_cast<AddressType const&>(_other);
+
+ return other.m_stateMutability <= m_stateMutability;
}
bool AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
+ if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
+ return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
return isImplicitlyConvertibleTo(_convertTo) ||
- _convertTo.category() == Category::Contract ||
_convertTo.category() == Category::Integer ||
(_convertTo.category() == Category::FixedBytes && 160 == dynamic_cast<FixedBytesType const&>(_convertTo).numBytes() * 8);
}
string AddressType::toString(bool) const
{
+ if (m_stateMutability == StateMutability::Payable)
+ return "address payable";
+ else
+ return "address";
+}
+
+string AddressType::canonicalName() const
+{
return "address";
}
@@ -461,7 +499,7 @@ u256 AddressType::literalValue(Literal const* _literal) const
{
solAssert(_literal, "");
solAssert(_literal->value().substr(0, 2) == "0x", "");
- return u256(_literal->value());
+ return u256(_literal->valueWithoutUnderscores());
}
TypePointer AddressType::unaryOperatorResult(Token::Value _operator) const
@@ -479,17 +517,29 @@ TypePointer AddressType::binaryOperatorResult(Token::Value _operator, TypePointe
return Type::commonType(shared_from_this(), _other);
}
+bool AddressType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ AddressType const& other = dynamic_cast<AddressType const&>(_other);
+ return other.m_stateMutability == m_stateMutability;
+}
+
MemberList::MemberMap AddressType::nativeMembers(ContractDefinition const*) const
{
- return {
+ MemberList::MemberMap members = {
{"balance", make_shared<IntegerType>(256)},
{"call", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)},
{"callcode", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)},
{"delegatecall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false)},
- {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)},
- {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)},
- {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)}
+ {"staticcall", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)}
};
+ if (m_stateMutability == StateMutability::Payable)
+ {
+ members.emplace_back(MemberList::Member{"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)});
+ members.emplace_back(MemberList::Member{"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)});
+ }
+ return members;
}
namespace
@@ -616,7 +666,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
return TypePointer();
}
- auto commonType = Type::commonType(shared_from_this(), _other); //might be a integer or fixed point
+ auto commonType = Type::commonType(shared_from_this(), _other); //might be an integer or fixed point
if (!commonType)
return TypePointer();
@@ -1226,13 +1276,13 @@ u256 RationalNumberType::literalValue(Literal const*) const
else
{
auto fixed = fixedPointType();
- solAssert(fixed, "");
+ solAssert(fixed, "Rational number cannot be represented as fixed point type.");
int fractionalDigits = fixed->fractionalDigits();
shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator();
}
// we ignore the literal and hope that the type was correctly determined
- solAssert(shiftedValue <= u256(-1), "Integer constant too large.");
+ solAssert(shiftedValue <= u256(-1), "Number constant too large.");
solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small.");
if (m_value >= rational(0))
@@ -1476,7 +1526,9 @@ bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- return isImplicitlyConvertibleTo(_convertTo) || _convertTo.category() == Category::Address;
+ if (auto const* addressType = dynamic_cast<AddressType const*>(&_convertTo))
+ return isPayable() || (addressType->stateMutability() < StateMutability::Payable);
+ return isImplicitlyConvertibleTo(_convertTo);
}
bool ContractType::isPayable() const
@@ -2074,8 +2126,11 @@ bool StructType::canBeUsedExternally(bool _inLibrary) const
// passed by value and thus the encoding does not differ, but it will disallow
// mappings.
for (auto const& var: m_struct.members())
+ {
+ solAssert(var->annotation().type, "");
if (!var->annotation().type->canBeUsedExternally(false))
return false;
+ }
}
return true;
}
@@ -2377,7 +2432,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
{
if (arrayType->isByteArray())
- // Return byte arrays as as whole.
+ // Return byte arrays as whole.
break;
returnType = arrayType->baseType();
m_parameterNames.push_back("");
@@ -2589,8 +2644,8 @@ bool FunctionType::operator==(Type const& _other) const
bool FunctionType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
- if (m_kind == Kind::External && _convertTo.category() == Category::Address)
- return true;
+ if (m_kind == Kind::External && _convertTo == AddressType::address())
+ return true;
return _convertTo.category() == category();
}
@@ -3275,7 +3330,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
{
case Kind::Block:
return MemberList::MemberMap({
- {"coinbase", make_shared<AddressType>()},
+ {"coinbase", make_shared<AddressType>(StateMutability::Payable)},
{"timestamp", make_shared<IntegerType>(256)},
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)},
{"difficulty", make_shared<IntegerType>(256)},
@@ -3284,7 +3339,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
});
case Kind::Message:
return MemberList::MemberMap({
- {"sender", make_shared<AddressType>()},
+ {"sender", make_shared<AddressType>(StateMutability::Payable)},
{"gas", make_shared<IntegerType>(256)},
{"value", make_shared<IntegerType>(256)},
{"data", make_shared<ArrayType>(DataLocation::CallData)},
@@ -3292,7 +3347,7 @@ MemberList::MemberMap MagicType::nativeMembers(ContractDefinition const*) const
});
case Kind::Transaction:
return MemberList::MemberMap({
- {"origin", make_shared<AddressType>()},
+ {"origin", make_shared<AddressType>(StateMutability::Payable)},
{"gasprice", make_shared<IntegerType>(256)}
});
case Kind::ABI:
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 7ee66838..0f3373a1 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -174,7 +174,7 @@ public:
/// Will not contain any character which would be invalid as an identifier.
std::string identifier() const;
- /// More complex identifier strings use "parentheses", where $_ is interpreted as as
+ /// More complex identifier strings use "parentheses", where $_ is interpreted as
/// "opening parenthesis", _$ as "closing parenthesis", _$_ as "comma" and any $ that
/// appears as part of a user-supplied identifier is escaped as _$$$_.
/// @returns an escaped identifier (will not contain any parenthesis or commas)
@@ -319,17 +319,21 @@ protected:
class AddressType: public Type
{
public:
+ static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
+ static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
+
virtual Category category() const override { return Category::Address; }
- explicit AddressType()
- {
- }
+ explicit AddressType(StateMutability _stateMutability);
virtual std::string richIdentifier() const override;
+ virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual bool operator==(Type const& _other) const override;
+
virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; }
virtual unsigned storageBytes() const override { return 160 / 8; }
virtual bool isValueType() const override { return true; }
@@ -337,11 +341,17 @@ public:
virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
virtual std::string toString(bool _short) const override;
+ virtual std::string canonicalName() const override;
virtual u256 literalValue(Literal const* _literal) const override;
virtual TypePointer encodingType() const override { return shared_from_this(); }
virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+
+ StateMutability stateMutability(void) const { return m_stateMutability; }
+
+private:
+ StateMutability m_stateMutability;
};
/**
@@ -354,6 +364,7 @@ public:
{
Unsigned, Signed
};
+
virtual Category category() const override { return Category::Integer; }
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
@@ -654,6 +665,9 @@ protected:
class ArrayType: public ReferenceType
{
public:
+ static ArrayType& bytesMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory)); return *addr; }
+ static ArrayType& stringMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory, true)); return *addr; }
+
virtual Category category() const override { return Category::Array; }
/// Constructor for a byte array ("bytes") and string.
@@ -755,7 +769,7 @@ public:
{
if (isSuper())
return TypePointer{};
- return std::make_shared<AddressType>();
+ return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable);
}
virtual TypePointer interfaceType(bool _inLibrary) const override
{
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index 5e5fe84a..6c27533c 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -242,8 +242,14 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
break;
}
case Type::Category::Contract:
- templ("body", "cleaned := " + cleanupFunction(AddressType()) + "(value)");
+ {
+ AddressType addressType(dynamic_cast<ContractType const&>(_type).isPayable() ?
+ StateMutability::Payable :
+ StateMutability::NonPayable
+ );
+ templ("body", "cleaned := " + cleanupFunction(addressType) + "(value)");
break;
+ }
case Type::Category::Enum:
{
size_t members = dynamic_cast<EnumType const&>(_type).numberOfMembers();
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp
index 2b77db8f..d33f749c 100644
--- a/libsolidity/codegen/ArrayUtils.cpp
+++ b/libsolidity/codegen/ArrayUtils.cpp
@@ -1108,8 +1108,6 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck) c
m_context << endTag;
break;
}
- default:
- solAssert(false, "");
}
}
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index e6ad6d9c..2bdf88e3 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -895,15 +895,6 @@ void CompilerUtils::convertType(
typeOnStack.location() == DataLocation::CallData,
"Invalid conversion to calldata type.");
break;
- default:
- solAssert(
- false,
- "Invalid type conversion " +
- _typeOnStack.toString(false) +
- " to " +
- _targetType.toString(false) +
- " requested."
- );
}
break;
}
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index ad3d7327..bd8170ad 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -260,7 +260,7 @@ public:
/// Stack post: <shifted_value>
void rightShiftNumberOnStack(unsigned _bits);
- /// Appends code that computes tha Keccak-256 hash of the topmost stack element of 32 byte type.
+ /// Appends code that computes the Keccak-256 hash of the topmost stack element of 32 byte type.
void computeHashStatic();
/// Bytes we need to the start of call data.
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 45e58bd0..27440289 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -710,9 +710,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments.front()->accept(*this);
// Optimization: If type is bytes or string, then do not encode,
// but directly compute keccak256 on memory.
- if (*argType == ArrayType(DataLocation::Memory) || *argType == ArrayType(DataLocation::Memory, true))
+ if (*argType == ArrayType::bytesMemory() || *argType == ArrayType::stringMemory())
{
- ArrayUtils(m_context).retrieveLength(ArrayType(DataLocation::Memory));
+ ArrayUtils(m_context).retrieveLength(ArrayType::bytesMemory());
m_context << Instruction::SWAP1 << u256(0x20) << Instruction::ADD;
}
else
@@ -1086,7 +1086,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().abiDecode(targetTypes, false);
else
{
- utils().convertType(*firstArgType, ArrayType(DataLocation::Memory));
+ utils().convertType(*firstArgType, ArrayType::bytesMemory());
m_context << Instruction::DUP1 << u256(32) << Instruction::ADD;
m_context << Instruction::SWAP1 << Instruction::MLOAD;
// stack now: <mem_pos> <length>
@@ -1098,8 +1098,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::GasLeft:
m_context << Instruction::GAS;
break;
- default:
- solAssert(false, "Invalid function type.");
}
}
return false;
@@ -1230,7 +1228,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
else
solAssert(false, "Contract member is neither variable nor function.");
m_context << identifier;
- /// need to store store it as bytes4
+ /// need to store it as bytes4
utils().leftShiftNumberOnStack(224);
return false;
}
@@ -1259,7 +1257,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
identifier = FunctionType(*function).externalIdentifier();
else
solAssert(false, "Contract member is neither variable nor function.");
- utils().convertType(type, AddressType(), true);
+ utils().convertType(type, type.isPayable() ? AddressType::addressPayable() : AddressType::address(), true);
m_context << identifier;
}
else
@@ -1277,15 +1275,24 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
{
utils().convertType(
*_memberAccess.expression().annotation().type,
- AddressType(),
+ AddressType::address(),
true
);
m_context << Instruction::BALANCE;
}
- else if ((set<string>{"send", "transfer", "call", "callcode", "delegatecall", "staticcall"}).count(member))
+ else if ((set<string>{"send", "transfer"}).count(member))
+ {
+ solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, "");
+ utils().convertType(
+ *_memberAccess.expression().annotation().type,
+ AddressType(StateMutability::Payable),
+ true
+ );
+ }
+ else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member))
utils().convertType(
*_memberAccess.expression().annotation().type,
- AddressType(),
+ AddressType::address(),
true
);
else
@@ -1296,7 +1303,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
if (member == "selector")
{
m_context << Instruction::SWAP1 << Instruction::POP;
- /// need to store store it as bytes4
+ /// need to store it as bytes4
utils().leftShiftNumberOnStack(224);
}
else
@@ -1966,7 +1973,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
m_context << dupInstruction(m_context.baseToCurrentStackOffset(contractStackPos));
bool existenceChecked = false;
- // Check the the target contract exists (has code) for non-low-level calls.
+ // Check the target contract exists (has code) for non-low-level calls.
if (funKind == FunctionType::Kind::External || funKind == FunctionType::Kind::DelegateCall)
{
m_context << Instruction::DUP1 << Instruction::EXTCODESIZE << Instruction::ISZERO;
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index 49c90405..19785817 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -639,8 +639,6 @@ void SMTChecker::checkCondition(
case smt::CheckResult::ERROR:
m_errorReporter.warning(_location, "Error trying to invoke SMT solver.");
break;
- default:
- solAssert(false, "");
}
m_interface->pop();
}
diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp
index 747c9172..9a0ccf48 100644
--- a/libsolidity/formal/Z3Interface.cpp
+++ b/libsolidity/formal/Z3Interface.cpp
@@ -91,8 +91,6 @@ pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _
case z3::check_result::unknown:
result = CheckResult::UNKNOWN;
break;
- default:
- solAssert(false, "");
}
if (result == CheckResult::SATISFIABLE && !_expressionsToEvaluate.empty())
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
index 9a0110cf..947b6d05 100644
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ b/libsolidity/inlineasm/AsmAnalysis.cpp
@@ -565,8 +565,10 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio
// We assume that returndatacopy, returndatasize and staticcall are either all available
// or all not available.
solAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), "");
+ // Similarly we assume bitwise shifting and create2 go together.
+ solAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), "");
- if (_instr == solidity::Instruction::CREATE2)
+ if (_instr == solidity::Instruction::EXTCODEHASH)
m_errorReporter.warning(
_location,
"The \"" +
@@ -593,7 +595,8 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio
else if ((
_instr == solidity::Instruction::SHL ||
_instr == solidity::Instruction::SHR ||
- _instr == solidity::Instruction::SAR
+ _instr == solidity::Instruction::SAR ||
+ _instr == solidity::Instruction::CREATE2
) && !m_evmVersion.hasBitwiseShifting())
m_errorReporter.warning(
_location,
diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h
index a7d7ead1..277e1879 100644
--- a/libsolidity/inlineasm/AsmCodeGen.h
+++ b/libsolidity/inlineasm/AsmCodeGen.h
@@ -41,7 +41,7 @@ struct Block;
class CodeGenerator
{
public:
- /// Performs code generation and appends generated to to _assembly.
+ /// Performs code generation and appends generated to _assembly.
static void assemble(
Block const& _parsedData,
AsmAnalysisInfo& _analysisInfo,
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index e800b278..d1001c80 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -128,7 +128,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool
bool CompilerStack::parse()
{
//reset
- if(m_stackState != SourcesSet)
+ if (m_stackState != SourcesSet)
return false;
m_errorReporter.clear();
ASTNode::resetID();
@@ -988,8 +988,7 @@ Json::Value CompilerStack::gasEstimates(string const& _contractName) const
if (eth::AssemblyItems const* items = assemblyItems(_contractName))
{
Gas executionGas = gasEstimator.functionalEstimation(*items);
- u256 bytecodeSize(runtimeObject(_contractName).bytecode.size());
- Gas codeDepositGas = bytecodeSize * eth::GasCosts::createDataGas;
+ Gas codeDepositGas{eth::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false)};
Json::Value creation(Json::objectValue);
creation["codeDepositCost"] = gasToJson(codeDepositGas);
diff --git a/libsolidity/interface/EVMVersion.h b/libsolidity/interface/EVMVersion.h
index b68e1f4e..657727ac 100644
--- a/libsolidity/interface/EVMVersion.h
+++ b/libsolidity/interface/EVMVersion.h
@@ -75,6 +75,7 @@ public:
bool supportsReturndata() const { return *this >= byzantium(); }
bool hasStaticCall() const { return *this >= byzantium(); }
bool hasBitwiseShifting() const { return *this >= constantinople(); }
+ bool hasCreate2() const { return *this >= constantinople(); }
/// Whether we have to retain the costs for the call opcode itself (false),
/// or whether we can just forward easily all remaining gas (true).
diff --git a/libsolidity/interface/Exceptions.cpp b/libsolidity/interface/Exceptions.cpp
index a837dce6..ecadd0b7 100644
--- a/libsolidity/interface/Exceptions.cpp
+++ b/libsolidity/interface/Exceptions.cpp
@@ -49,9 +49,6 @@ Error::Error(Type _type, SourceLocation const& _location, string const& _descrip
case Type::Warning:
m_typeName = "Warning";
break;
- default:
- solAssert(false, "");
- break;
}
if (!_location.isEmpty())
diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp
index a532f86e..e70e23a2 100644
--- a/libsolidity/interface/GasEstimator.cpp
+++ b/libsolidity/interface/GasEstimator.cpp
@@ -160,8 +160,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
);
}
- PathGasMeter meter(_items, m_evmVersion);
- return meter.estimateMax(0, state);
+ return PathGasMeter::estimateMax(_items, m_evmVersion, 0, state);
}
GasEstimator::GasConsumption GasEstimator::functionalEstimation(
@@ -183,7 +182,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation(
if (parametersSize > 0)
state->feedItem(swapInstruction(parametersSize));
- return PathGasMeter(_items, m_evmVersion).estimateMax(_offset, state);
+ return PathGasMeter::estimateMax(_items, m_evmVersion, _offset, state);
}
set<ASTNode const*> GasEstimator::finestNodesAtLocation(
diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp
index a8716862..11dde349 100644
--- a/libsolidity/interface/Natspec.cpp
+++ b/libsolidity/interface/Natspec.cpp
@@ -83,7 +83,8 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef)
doc["details"] = Json::Value(dev);
auto constructorDefinition(_contractDef.constructor());
- if (constructorDefinition) {
+ if (constructorDefinition)
+ {
Json::Value constructor(devDocumentation(constructorDefinition->annotation().docTags));
if (!constructor.empty())
// add the constructor, only if we have any documentation to add
diff --git a/libsolidity/interface/SourceReferenceFormatter.cpp b/libsolidity/interface/SourceReferenceFormatter.cpp
index 0f014372..865907e2 100644
--- a/libsolidity/interface/SourceReferenceFormatter.cpp
+++ b/libsolidity/interface/SourceReferenceFormatter.cpp
@@ -55,8 +55,15 @@ void SourceReferenceFormatter::printSourceLocation(SourceLocation const* _locati
}
if (line.length() > 150)
{
- line = " ... " + line.substr(startColumn, locationLength) + " ... ";
- startColumn = 5;
+ int len = line.length();
+ line = line.substr(max(0, startColumn - 35), min(startColumn, 35) + min(locationLength + 35, len - startColumn));
+ if (startColumn + locationLength + 35 < len)
+ line += " ...";
+ if (startColumn > 35)
+ {
+ line = " ... " + line;
+ startColumn = 40;
+ }
endColumn = startColumn + locationLength;
}
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index c1996777..2305da13 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -280,6 +280,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
for (auto const& url: sources[sourceName]["urls"])
{
+ if (!url.isString())
+ return formatFatalError("JSONError", "URL must be a string.");
ReadCallback::Result result = m_readFile(url.asString());
if (result.success)
{
@@ -320,7 +322,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
if (settings.isMember("evmVersion"))
{
- boost::optional<EVMVersion> version = EVMVersion::fromString(settings.get("evmVersion", {}).asString());
+ if (!settings["evmVersion"].isString())
+ return formatFatalError("JSONError", "evmVersion must be a string.");
+ boost::optional<EVMVersion> version = EVMVersion::fromString(settings["evmVersion"].asString());
if (!version)
return formatFatalError("JSONError", "Invalid EVM version requested.");
m_compilerStack.setEVMVersion(*version);
@@ -329,6 +333,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
vector<CompilerStack::Remapping> remappings;
for (auto const& remapping: settings.get("remappings", Json::Value()))
{
+ if (!remapping.isString())
+ return formatFatalError("JSONError", "Remapping entry must be a string.");
if (auto r = CompilerStack::parseRemapping(remapping.asString()))
remappings.emplace_back(std::move(*r));
else
@@ -336,10 +342,25 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
}
m_compilerStack.setRemappings(remappings);
- Json::Value optimizerSettings = settings.get("optimizer", Json::Value());
- bool const optimize = optimizerSettings.get("enabled", Json::Value(false)).asBool();
- unsigned const optimizeRuns = optimizerSettings.get("runs", Json::Value(200u)).asUInt();
- m_compilerStack.setOptimiserSettings(optimize, optimizeRuns);
+ if (settings.isMember("optimizer"))
+ {
+ Json::Value optimizerSettings = settings["optimizer"];
+ if (optimizerSettings.isMember("enabled"))
+ {
+ if (!optimizerSettings["enabled"].isBool())
+ return formatFatalError("JSONError", "The \"enabled\" setting must be a boolean.");
+
+ bool const optimize = optimizerSettings["enabled"].asBool();
+ unsigned optimizeRuns = 200;
+ if (optimizerSettings.isMember("runs"))
+ {
+ if (!optimizerSettings["runs"].isUInt())
+ return formatFatalError("JSONError", "The \"runs\" setting must be an unsigned number.");
+ optimizeRuns = optimizerSettings["runs"].asUInt();
+ }
+ m_compilerStack.setOptimiserSettings(optimize, optimizeRuns);
+ }
+ }
map<string, h160> libraries;
Json::Value jsonLibraries = settings.get("libraries", Json::Value(Json::objectValue));
@@ -349,9 +370,11 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
{
auto const& jsonSourceName = jsonLibraries[sourceName];
if (!jsonSourceName.isObject())
- return formatFatalError("JSONError", "library entry is not a JSON object.");
+ return formatFatalError("JSONError", "Library entry is not a JSON object.");
for (auto const& library: jsonSourceName.getMemberNames())
{
+ if (!jsonSourceName[library].isString())
+ return formatFatalError("JSONError", "Library address must be a string.");
string address = jsonSourceName[library].asString();
if (!boost::starts_with(address, "0x"))
@@ -607,7 +630,7 @@ string StandardCompiler::compile(string const& _input) noexcept
}
catch (...)
{
- return "{\"errors\":\"[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error parsing input JSON.\"}]}";
+ return "{\"errors\":[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error parsing input JSON.\"}]}";
}
// cout << "Input: " << input.toStyledString() << endl;
@@ -620,6 +643,6 @@ string StandardCompiler::compile(string const& _input) noexcept
}
catch (...)
{
- return "{\"errors\":\"[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error writing output JSON.\"}]}";
+ return "{\"errors\":[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error writing output JSON.\"}]}";
}
}
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index 0c41e332..1228b833 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -57,7 +57,7 @@ public:
solAssert(m_location.sourceName, "");
if (m_location.end < 0)
markEndPosition();
- return make_shared<NodeType>(m_location, forward<Args>(_args)...);
+ return make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
}
private:
@@ -813,8 +813,24 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
unsigned secondSize;
tie(firstSize, secondSize) = m_scanner->currentTokenInfo();
ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize);
- type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(elemTypeName);
+ ASTNodeFactory nodeFactory(*this);
+ nodeFactory.markEndPosition();
m_scanner->next();
+ auto stateMutability = boost::make_optional(elemTypeName.token() == Token::Address, StateMutability::NonPayable);
+ if (Token::isStateMutabilitySpecifier(m_scanner->currentToken(), false))
+ {
+ if (elemTypeName.token() == Token::Address)
+ {
+ nodeFactory.markEndPosition();
+ stateMutability = parseStateMutability();
+ }
+ else
+ {
+ parserError("State mutability can only be specified for address types.");
+ m_scanner->next();
+ }
+ }
+ type = nodeFactory.createNode<ElementaryTypeName>(elemTypeName, stateMutability);
}
else if (token == Token::Var)
{
@@ -1615,8 +1631,8 @@ Parser::LookAheadInfo Parser::peekStatementType() const
// Distinguish between variable declaration (and potentially assignment) and expression statement
// (which include assignments to other expressions and pre-declared variables).
// We have a variable declaration if we get a keyword that specifies a type name.
- // If it is an identifier or an elementary type name followed by an identifier, we also have
- // a variable declaration.
+ // If it is an identifier or an elementary type name followed by an identifier
+ // or a mutability specifier, we also have a variable declaration.
// If we get an identifier followed by a "[" or ".", it can be both ("lib.type[9] a;" or "variable.el[9] = 7;").
// In all other cases, we have an expression statement.
Token::Value token(m_scanner->currentToken());
@@ -1627,6 +1643,12 @@ Parser::LookAheadInfo Parser::peekStatementType() const
if (mightBeTypeName)
{
Token::Value next = m_scanner->peekNextToken();
+ // So far we only allow ``address payable`` in variable declaration statements and in no other
+ // kind of statement. This means, for example, that we do not allow type expressions of the form
+ // ``address payable;``.
+ // If we want to change this in the future, we need to consider another scanner token here.
+ if (Token::isElementaryTypeName(token) && Token::isStateMutabilitySpecifier(next, false))
+ return LookAheadInfo::VariableDeclaration;
if (next == Token::Identifier || Token::isLocationSpecifier(next))
return LookAheadInfo::VariableDeclaration;
if (next == Token::LBrack || next == Token::Period)
diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp
index c9d5b969..9a7f85cb 100644
--- a/libsolidity/parsing/Scanner.cpp
+++ b/libsolidity/parsing/Scanner.cpp
@@ -601,7 +601,7 @@ void Scanner::scanToken()
{
tie(token, m, n) = scanIdentifierOrKeyword();
- // Special case for hexademical literals
+ // Special case for hexadecimal literals
if (token == Token::Hex)
{
// reset
@@ -780,13 +780,13 @@ Token::Value Scanner::scanNumber(char _charSeen)
{
addLiteralCharAndAdvance();
// either 0, 0exxx, 0Exxx, 0.xxx or a hex number
- if (m_char == 'x' || m_char == 'X')
+ if (m_char == 'x')
{
// hex number
kind = HEX;
addLiteralCharAndAdvance();
if (!isHexDigit(m_char))
- return Token::Illegal; // we must have at least one hex digit after 'x'/'X'
+ return Token::Illegal; // we must have at least one hex digit after 'x'
while (isHexDigit(m_char) || m_char == '_') // We keep the underscores for later validation
addLiteralCharAndAdvance();
diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h
index 7ce24e69..73c85482 100644
--- a/libsolidity/parsing/Token.h
+++ b/libsolidity/parsing/Token.h
@@ -312,7 +312,12 @@ public:
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage || op == CallData; }
- static bool isStateMutabilitySpecifier(Value op) { return op == Pure || op == Constant || op == View || op == Payable; }
+ static bool isStateMutabilitySpecifier(Value op, bool _allowConstant = true)
+ {
+ if (op == Constant && _allowConstant)
+ return true;
+ return op == Pure || op == View || op == Payable;
+ }
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= Unchecked); }
diff --git a/scripts/check_style.sh b/scripts/check_style.sh
new file mode 100755
index 00000000..a8557a54
--- /dev/null
+++ b/scripts/check_style.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+REPO_ROOT="$(dirname "$0")"/..
+
+(
+cd $REPO_ROOT
+WHITESPACE=$(git grep -n -I -E "^.*[[:space:]]+$" | grep -v "test/libsolidity/ASTJSON\|test/compilationTests/zeppelin/LICENSE")
+
+if [[ "$WHITESPACE" != "" ]]
+then
+ echo "Error: Trailing whitespace found:" >&2
+ echo "$WHITESPACE" >&2
+ exit 1
+fi
+)
+
+(
+cd $REPO_ROOT
+FORMATERROR=$(
+(
+git grep -nIE "\<(if|for)\(" -- '*.h' '*.cpp'
+git grep -nIE "\<if\>\s*\(.*\)\s*\{\s*$" -- '*.h' '*.cpp'
+) | egrep -v "^[a-zA-Z\./]*:[0-9]*:\s*\/(\/|\*)" | egrep -v "^test/"
+)
+
+if [[ "$FORMATERROR" != "" ]]
+then
+ echo "Error: Format error for if/for:" >&2
+ echo "$FORMATERROR" >&2
+ exit 1
+fi
+)
diff --git a/scripts/codespell_whitelist.txt b/scripts/codespell_whitelist.txt
index 31f03981..0f5013cb 100644
--- a/scripts/codespell_whitelist.txt
+++ b/scripts/codespell_whitelist.txt
@@ -1,3 +1,4 @@
iff
nd
assignend
+uint
diff --git a/scripts/detect_trailing_whitespace.sh b/scripts/detect_trailing_whitespace.sh
deleted file mode 100755
index 1a136a10..00000000
--- a/scripts/detect_trailing_whitespace.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-
-REPO_ROOT="$(dirname "$0")"/..
-
-(
-cd $REPO_ROOT
-WHITESPACE=$(git grep -n -I -E "^.*[[:space:]]+$" | grep -v "test/libsolidity/ASTJSON\|test/compilationTests/zeppelin/LICENSE")
-
-if [[ "$WHITESPACE" != "" ]]
-then
- echo "Error: Trailing whitespace found:" >&2
- echo "$WHITESPACE" >&2
- exit 1
-fi
-)
diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh
index 96501499..b107f7c9 100755
--- a/scripts/install_deps.sh
+++ b/scripts/install_deps.sh
@@ -87,9 +87,12 @@ case $(uname -s) in
10.13)
echo "Installing solidity dependencies on macOS 10.13 High Sierra."
;;
+ 10.14)
+ echo "Installing solidity dependencies on macOS 10.14 Mojave."
+ ;;
*)
echo "Unsupported macOS version."
- echo "We only support Mavericks, Yosemite, El Capitan, Sierra and High Sierra."
+ echo "We only support Mavericks, Yosemite, El Capitan, Sierra, High Sierra and Mojave."
exit 1
;;
esac
diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py
index 06e9f9ea..8a9aa0a7 100755
--- a/scripts/isolate_tests.py
+++ b/scripts/isolate_tests.py
@@ -56,9 +56,10 @@ def extract_docs_cases(path):
if re.search(r'^ [ ]*(pragma solidity|contract |library |interface )', test, re.MULTILINE)
]
-def write_cases(tests):
+def write_cases(f, tests):
+ cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower()
for test in tests:
- open('test_%s.sol' % hashlib.sha256(test).hexdigest(), 'wb').write(test)
+ open('test_%s_%s.sol' % (hashlib.sha256(test).hexdigest(), cleaned_filename), 'wb').write(test)
def extract_and_write(f, path):
@@ -69,7 +70,7 @@ def extract_and_write(f, path):
cases = [open(path, 'r').read()]
else:
cases = extract_test_cases(path)
- write_cases(cases)
+ write_cases(f, cases)
if __name__ == '__main__':
path = sys.argv[1]
diff --git a/scripts/tests.sh b/scripts/tests.sh
index 1c0fc590..c284c05c 100755
--- a/scripts/tests.sh
+++ b/scripts/tests.sh
@@ -100,8 +100,14 @@ else
log_directory=""
fi
-function printError() { echo "$(tput setaf 1)$1$(tput sgr0)"; }
-function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput sgr0)"; }
+if [ "$CIRCLECI" ]
+then
+ function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput setaf 7)"; }
+ function printError() { echo "$(tput setaf 1)$1$(tput setaf 7)"; }
+else
+ function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput sgr0)"; }
+ function printError() { echo "$(tput setaf 1)$1$(tput sgr0)"; }
+fi
printTask "Running commandline tests..."
# Only run in parallel if this is run on CI infrastructure
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index f7d1c748..8fd0d6ef 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -736,13 +736,15 @@ bool CommandLineInterface::processInput()
if (m_args.count(g_argAllowPaths))
{
vector<string> paths;
- for (string const& path: boost::split(paths, m_args[g_argAllowPaths].as<string>(), boost::is_any_of(","))) {
+ for (string const& path: boost::split(paths, m_args[g_argAllowPaths].as<string>(), boost::is_any_of(",")))
+ {
auto filesystem_path = boost::filesystem::path(path);
// If the given path had a trailing slash, the Boost filesystem
// path will have it's last component set to '.'. This breaks
// path comparison in later parts of the code, so we need to strip
// it.
- if (filesystem_path.filename() == ".") {
+ if (filesystem_path.filename() == ".")
+ {
filesystem_path.remove_filename();
}
m_allowedDirectories.push_back(filesystem_path);
diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp
index ea624735..3922d5e9 100644
--- a/test/ExecutionFramework.cpp
+++ b/test/ExecutionFramework.cpp
@@ -122,9 +122,9 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
if (!_isCreation)
{
d.to = dev::toString(m_contractAddress);
- BOOST_REQUIRE(m_rpc.eth_getCode(d.to, "latest").size() > 2);
+ BOOST_REQUIRE(m_rpc.eth_getCode(d.to, "pending").size() > 2);
// Use eth_call to get the output
- m_output = fromHex(m_rpc.eth_call(d, "latest"), WhenError::Throw);
+ m_output = fromHex(m_rpc.eth_call(d, "pending"), WhenError::Throw);
}
string txHash = m_rpc.eth_sendTransaction(d);
diff --git a/test/Options.cpp b/test/Options.cpp
index ff4a7c98..63588237 100644
--- a/test/Options.cpp
+++ b/test/Options.cpp
@@ -25,9 +25,11 @@
#include <libsolidity/interface/Exceptions.h>
#include <boost/test/framework.hpp>
+#include <boost/filesystem.hpp>
using namespace std;
using namespace dev::test;
+namespace fs = boost::filesystem;
Options const& Options::get()
{
@@ -70,6 +72,27 @@ Options::Options()
if (testPath.empty())
if (auto path = getenv("ETH_TEST_PATH"))
testPath = path;
+
+ if (testPath.empty())
+ {
+ auto const searchPath =
+ {
+ fs::current_path() / ".." / ".." / ".." / "test",
+ fs::current_path() / ".." / ".." / "test",
+ fs::current_path() / ".." / "test",
+ fs::current_path() / "test",
+ fs::current_path()
+ };
+ for (auto const& basePath : searchPath)
+ {
+ fs::path syntaxTestPath = basePath / "libsolidity" / "syntaxTests";
+ if (fs::exists(syntaxTestPath) && fs::is_directory(syntaxTestPath))
+ {
+ testPath = basePath;
+ break;
+ }
+ }
+ }
}
void Options::validate() const
diff --git a/test/cmdlineErrorReports/too_long_line.sol b/test/cmdlineErrorReports/too_long_line.sol
new file mode 100644
index 00000000..7df1057a
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line.sol
@@ -0,0 +1,4 @@
+contract C {
+ function ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(announcementType Type, string Announcement, string Link, bool Oppositable, string _str, uint256 _uint, address _addr) onlyOwner external {
+}
+}
diff --git a/test/cmdlineErrorReports/too_long_line.sol.ref b/test/cmdlineErrorReports/too_long_line.sol.ref
new file mode 100644
index 00000000..7cad93ee
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line.sol.ref
@@ -0,0 +1,7 @@
+
+too_long_line.sol:1:1: Warning: Source file does not specify required compiler version!
+contract C {
+^ (Relevant source part starts here and spans across multiple lines).
+too_long_line.sol:2:164: Error: Identifier not found or not unique.
+ ... ffffffffffffffffffffffffffffffffff(announcementType Type, string Announcement, string ...
+ ^--------------^
diff --git a/test/cmdlineErrorReports/too_long_line_both_sides_short.sol b/test/cmdlineErrorReports/too_long_line_both_sides_short.sol
new file mode 100644
index 00000000..062f0292
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_both_sides_short.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(announcementTypeXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Type,
+ string Announcement, string Link, bool Oppositable, string _str, uint256 _uint, address _addr) onlyOwner external {
+}
+}
diff --git a/test/cmdlineErrorReports/too_long_line_both_sides_short.sol.ref b/test/cmdlineErrorReports/too_long_line_both_sides_short.sol.ref
new file mode 100644
index 00000000..f2ea427a
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_both_sides_short.sol.ref
@@ -0,0 +1,7 @@
+
+too_long_line_both_sides_short.sol:1:1: Warning: Source file does not specify required compiler version!
+contract C {
+^ (Relevant source part starts here and spans across multiple lines).
+too_long_line_both_sides_short.sol:2:15: Error: Identifier not found or not unique.
+ function f(announcementTypeXXXXXXXXXXXXXXXXXXX ... XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Type,
+ ^-------------------------------------------------------------------------^
diff --git a/test/cmdlineErrorReports/too_long_line_edge_in.sol b/test/cmdlineErrorReports/too_long_line_edge_in.sol
new file mode 100644
index 00000000..6f181c83
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_edge_in.sol
@@ -0,0 +1,4 @@
+contract C {
+ function ffffffffffffffffffffff(announcementTypeTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Ty, string A) onlyOwner external {
+}
+}
diff --git a/test/cmdlineErrorReports/too_long_line_edge_in.sol.ref b/test/cmdlineErrorReports/too_long_line_edge_in.sol.ref
new file mode 100644
index 00000000..b6699933
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_edge_in.sol.ref
@@ -0,0 +1,7 @@
+
+too_long_line_edge_in.sol:1:1: Warning: Source file does not specify required compiler version!
+contract C {
+^ (Relevant source part starts here and spans across multiple lines).
+too_long_line_edge_in.sol:2:36: Error: Identifier not found or not unique.
+ function ffffffffffffffffffffff(announcementTypeTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Ty, string A) onlyOwner external {
+ ^----------------------------------------------------------------------------------------------^
diff --git a/test/cmdlineErrorReports/too_long_line_edge_out.sol b/test/cmdlineErrorReports/too_long_line_edge_out.sol
new file mode 100644
index 00000000..29d3cee6
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_edge_out.sol
@@ -0,0 +1,4 @@
+contract C {
+ function fffffffffffffffffffffff(announcementTypeTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Typ, string A) onlyOwner external {
+}
+}
diff --git a/test/cmdlineErrorReports/too_long_line_edge_out.sol.ref b/test/cmdlineErrorReports/too_long_line_edge_out.sol.ref
new file mode 100644
index 00000000..76df589a
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_edge_out.sol.ref
@@ -0,0 +1,7 @@
+
+too_long_line_edge_out.sol:1:1: Warning: Source file does not specify required compiler version!
+contract C {
+^ (Relevant source part starts here and spans across multiple lines).
+too_long_line_edge_out.sol:2:37: Error: Identifier not found or not unique.
+ ... function fffffffffffffffffffffff(announcementTypeTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT Typ, string A) onlyOwner external ...
+ ^----------------------------------------------------------------------------------------------^
diff --git a/test/cmdlineErrorReports/too_long_line_left_short.sol b/test/cmdlineErrorReports/too_long_line_left_short.sol
new file mode 100644
index 00000000..2accfcce
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_left_short.sol
@@ -0,0 +1,4 @@
+contract C {
+ function f(announcementType Type, string Announcement, string Link, bool Oppositable, string _str, uint256 _uint, address _addr) onlyOwner external {
+}
+}
diff --git a/test/cmdlineErrorReports/too_long_line_left_short.sol.ref b/test/cmdlineErrorReports/too_long_line_left_short.sol.ref
new file mode 100644
index 00000000..efaa559d
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_left_short.sol.ref
@@ -0,0 +1,7 @@
+
+too_long_line_left_short.sol:1:1: Warning: Source file does not specify required compiler version!
+contract C {
+^ (Relevant source part starts here and spans across multiple lines).
+too_long_line_left_short.sol:2:15: Error: Identifier not found or not unique.
+ function f(announcementType Type, string Announcement, string ...
+ ^--------------^
diff --git a/test/cmdlineErrorReports/too_long_line_right_short.sol b/test/cmdlineErrorReports/too_long_line_right_short.sol
new file mode 100644
index 00000000..936b3961
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_right_short.sol
@@ -0,0 +1,5 @@
+contract C {
+ function ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(announcementType Type,
+ string Announcement, string Link, bool Oppositable, string _str, uint256 _uint, address _addr) onlyOwner external {
+}
+}
diff --git a/test/cmdlineErrorReports/too_long_line_right_short.sol.ref b/test/cmdlineErrorReports/too_long_line_right_short.sol.ref
new file mode 100644
index 00000000..2b0c6d8c
--- /dev/null
+++ b/test/cmdlineErrorReports/too_long_line_right_short.sol.ref
@@ -0,0 +1,7 @@
+
+too_long_line_right_short.sol:1:1: Warning: Source file does not specify required compiler version!
+contract C {
+^ (Relevant source part starts here and spans across multiple lines).
+too_long_line_right_short.sol:2:164: Error: Identifier not found or not unique.
+ ... ffffffffffffffffffffffffffffffffff(announcementType Type,
+ ^--------------^
diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh
index 6f8a8ac1..d7b95e8a 100755
--- a/test/cmdlineTests.sh
+++ b/test/cmdlineTests.sh
@@ -37,9 +37,15 @@ FULLARGS="--optimize --ignore-missing --combined-json abi,asm,ast,bin,bin-runtim
echo "Checking that the bug list is up to date..."
"$REPO_ROOT"/scripts/update_bugs_by_version.py
-function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput sgr0)"; }
+if [ "$CIRCLECI" ]
+then
+ function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput setaf 7)"; }
+ function printError() { echo "$(tput setaf 1)$1$(tput setaf 7)"; }
+else
+ function printTask() { echo "$(tput bold)$(tput setaf 2)$1$(tput sgr0)"; }
+ function printError() { echo "$(tput setaf 1)$1$(tput sgr0)"; }
+fi
-function printError() { echo "$(tput setaf 1)$1$(tput sgr0)"; }
function compileFull()
{
@@ -117,6 +123,8 @@ test_solc_file_input_failures() {
exitCode=$?
set -e
+ stderr=`sed 's/.*This is a pre-release compiler version, please do not use it in production.*$//' $stderr_path`
+
if [[ $exitCode -eq 0 ]]; then
printError "Incorrect exit code. Expected failure (non-zero) but got success (0)."
rm -f $stdout_path $stderr_path
@@ -133,12 +141,12 @@ test_solc_file_input_failures() {
exit 1
fi
- if [[ "$(cat $stderr_path)" != "${stderr_expected}" ]]; then
+ if [[ "$stderr" != "${stderr_expected}" ]]; then
printError "Incorrect output on stderr received. Expected:"
echo -e "${stderr_expected}"
printError "But got:"
- cat $stderr_path
+ echo $stderr
rm -f $stdout_path $stderr_path
exit 1
fi
@@ -156,6 +164,16 @@ printTask "Testing passing empty remappings..."
test_solc_file_input_failures "${0}" "=/some/remapping/target" "" "Invalid remapping: \"=/some/remapping/target\"."
test_solc_file_input_failures "${0}" "ctx:=/some/remapping/target" "" "Invalid remapping: \"ctx:=/some/remapping/target\"."
+printTask "Testing passing location printing..."
+(
+cd "$REPO_ROOT"/test/cmdlineErrorReports/
+for file in *.sol
+do
+ ret=`cat $file.ref`
+ test_solc_file_input_failures "$file" "" "" "$ret"
+done
+)
+
printTask "Compiling various other contracts and libraries..."
(
cd "$REPO_ROOT"/test/compilationTests/
@@ -165,6 +183,8 @@ do
then
echo " - $dir"
cd "$dir"
+ # Replace version pragmas
+ find . -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity [\^0-9\.]*/pragma solidity >=0.0/'
compileFull -w *.sol */*.sol
cd ..
fi
diff --git a/test/compilationTests/corion/ico.sol b/test/compilationTests/corion/ico.sol
index b1e0bf75..e660389b 100644
--- a/test/compilationTests/corion/ico.sol
+++ b/test/compilationTests/corion/ico.sol
@@ -27,12 +27,12 @@ contract ico is safeMath {
uint256 constant oneSegment = 40320;
- address public owner;
- address public tokenAddr;
- address public premiumAddr;
+ address payable public owner;
+ address payable public tokenAddr;
+ address payable public premiumAddr;
uint256 public startBlock;
uint256 public icoDelay;
- address public foundationAddress;
+ address payable public foundationAddress;
address public icoEtcPriceAddr;
uint256 public icoExchangeRate;
uint256 public icoExchangeRateSetBlock;
@@ -50,7 +50,7 @@ contract ico is safeMath {
uint256 public totalMint;
uint256 public totalPremiumMint;
- constructor(address foundation, address priceSet, uint256 exchangeRate, uint256 startBlockNum, address[] memory genesisAddr, uint256[] memory genesisValue) public {
+ constructor(address payable foundation, address priceSet, uint256 exchangeRate, uint256 startBlockNum, address[] memory genesisAddr, uint256[] memory genesisValue) public {
/*
Installation function.
@@ -248,7 +248,7 @@ contract ico is safeMath {
aborted = true;
}
- function connectTokens(address tokenContractAddr, address premiumContractAddr) external {
+ function connectTokens(address payable tokenContractAddr, address payable premiumContractAddr) external {
/*
Installation function which joins the two token contracts with this contract.
Only callable by the owner
@@ -284,7 +284,7 @@ contract ico is safeMath {
require( buy(msg.sender, address(0x00)) );
}
- function buy(address beneficiaryAddress, address affilateAddress) public payable returns (bool success) {
+ function buy(address payable beneficiaryAddress, address affilateAddress) public payable returns (bool success) {
/*
Buying a token
diff --git a/test/compilationTests/corion/module.sol b/test/compilationTests/corion/module.sol
index da4dd344..bd6952b1 100644
--- a/test/compilationTests/corion/module.sol
+++ b/test/compilationTests/corion/module.sol
@@ -1,8 +1,8 @@
pragma solidity ^0.4.11;
contract abstractModuleHandler {
- function transfer(address from, address to, uint256 value, bool fee) external returns (bool success) {}
- function balanceOf(address owner) public view returns (bool success, uint256 value) {}
+ function transfer(address payable from, address payable to, uint256 value, bool fee) external returns (bool success) {}
+ function balanceOf(address payable owner) public view returns (bool success, uint256 value) {}
}
contract module {
@@ -19,7 +19,7 @@ contract module {
status public moduleStatus;
uint256 public disabledUntil;
- address public moduleHandlerAddress;
+ address payable public moduleHandlerAddress;
function disableModule(bool forever) external onlyForModuleHandler returns (bool success) {
_disableModule(forever);
@@ -36,11 +36,11 @@ contract module {
else { disabledUntil = block.number + 5760; }
}
- function replaceModuleHandler(address newModuleHandlerAddress) external onlyForModuleHandler returns (bool success) {
+ function replaceModuleHandler(address payable newModuleHandlerAddress) external onlyForModuleHandler returns (bool success) {
_replaceModuleHandler(newModuleHandlerAddress);
return true;
}
- function _replaceModuleHandler(address newModuleHandlerAddress) internal {
+ function _replaceModuleHandler(address payable newModuleHandlerAddress) internal {
/*
Replace the ModuleHandler address.
This function calls the Publisher module.
@@ -77,11 +77,11 @@ contract module {
moduleStatus = status.Disconnected;
}
- function replaceModule(address newModuleAddress) external onlyForModuleHandler returns (bool success) {
+ function replaceModule(address payable newModuleAddress) external onlyForModuleHandler returns (bool success) {
_replaceModule(newModuleAddress);
return true;
}
- function _replaceModule(address newModuleAddress) internal {
+ function _replaceModule(address payable newModuleAddress) internal {
/*
Replace the module for an another new module.
This function calls the Publisher module.
@@ -101,20 +101,20 @@ contract module {
moduleStatus = status.Disconnected;
}
- function transferEvent(address from, address to, uint256 value) external onlyForModuleHandler returns (bool success) {
+ function transferEvent(address payable from, address payable to, uint256 value) external onlyForModuleHandler returns (bool success) {
return true;
}
function newSchellingRoundEvent(uint256 roundID, uint256 reward) external onlyForModuleHandler returns (bool success) {
return true;
}
- function registerModuleHandler(address _moduleHandlerAddress) internal {
+ function registerModuleHandler(address payable _moduleHandlerAddress) internal {
/*
Module constructor function for registering ModuleHandler address.
*/
moduleHandlerAddress = _moduleHandlerAddress;
}
- function isModuleHandler(address addr) internal returns (bool ret) {
+ function isModuleHandler(address payable addr) internal returns (bool ret) {
/*
Test for ModuleHandler address.
If the module is not connected then returns always false.
@@ -140,4 +140,6 @@ contract module {
require( msg.sender == moduleHandlerAddress );
_;
}
+ function() external payable {
+ }
}
diff --git a/test/compilationTests/corion/moduleHandler.sol b/test/compilationTests/corion/moduleHandler.sol
index 2b513eb1..6b0daf0d 100644
--- a/test/compilationTests/corion/moduleHandler.sol
+++ b/test/compilationTests/corion/moduleHandler.sol
@@ -25,7 +25,7 @@ contract abstractModule {
contract moduleHandler is multiOwner, announcementTypes {
struct modules_s {
- address addr;
+ address payable addr;
bytes32 name;
bool schellingEvent;
bool transferEvent;
@@ -37,7 +37,7 @@ contract moduleHandler is multiOwner, announcementTypes {
constructor(address[] memory newOwners) multiOwner(newOwners) public {}
- function load(address foundation, bool forReplace, address Token, address Premium, address Publisher, address Schelling, address Provider) public {
+ function load(address payable foundation, bool forReplace, address payable Token, address payable Premium, address payable Publisher, address payable Schelling, address payable Provider) public {
/*
Loading modulest to ModuleHandler.
@@ -140,7 +140,7 @@ contract moduleHandler is multiOwner, announcementTypes {
}
return (true, false, 0);
}
- function replaceModule(string calldata name, address addr, bool callCallback) external returns (bool success) {
+ function replaceModule(string calldata name, address payable addr, bool callCallback) external returns (bool success) {
/*
Module replace, can be called only by the Publisher contract.
@@ -178,7 +178,7 @@ contract moduleHandler is multiOwner, announcementTypes {
return true;
}
- function newModule(string calldata name, address addr, bool schellingEvent, bool transferEvent) external returns (bool success) {
+ function newModule(string calldata name, address payable addr, bool schellingEvent, bool transferEvent) external returns (bool success) {
/*
Adding new module to the database. Can be called only by the Publisher contract.
diff --git a/test/compilationTests/corion/premium.sol b/test/compilationTests/corion/premium.sol
index 84277a99..4952a740 100644
--- a/test/compilationTests/corion/premium.sol
+++ b/test/compilationTests/corion/premium.sol
@@ -12,7 +12,7 @@ contract thirdPartyPContractAbstract {
contract ptokenDB is tokenDB {}
contract premium is module, safeMath {
- function replaceModule(address addr) external returns (bool success) {
+ function replaceModule(address payable addr) external returns (bool success) {
require( super.isModuleHandler(msg.sender) );
require( db.replaceOwner(addr) );
super._replaceModule(addr);
@@ -40,7 +40,7 @@ contract premium is module, safeMath {
mapping(address => bool) public genesis;
- constructor(bool forReplace, address moduleHandler, address dbAddress, address icoContractAddr, address[] memory genesisAddr, uint256[] memory genesisValue) public {
+ constructor(bool forReplace, address payable moduleHandler, address dbAddress, address icoContractAddr, address[] memory genesisAddr, uint256[] memory genesisValue) public {
/*
Setup function.
If an ICOaddress is defined then the balance of the genesis addresses will be set as well.
diff --git a/test/compilationTests/corion/provider.sol b/test/compilationTests/corion/provider.sol
index 41857e54..b3b5e8ca 100644
--- a/test/compilationTests/corion/provider.sol
+++ b/test/compilationTests/corion/provider.sol
@@ -16,7 +16,7 @@ contract provider is module, safeMath, announcementTypes {
require( _success );
return true;
}
- function transferEvent(address from, address to, uint256 value) external returns (bool success) {
+ function transferEvent(address payable from, address payable to, uint256 value) external returns (bool success) {
/*
Transaction completed. This function is only available for the modulehandler.
It should be checked if the sender or the acceptor does not connect to the provider or it is not a provider itself if so than the change should be recorded.
@@ -118,7 +118,7 @@ contract provider is module, safeMath, announcementTypes {
uint256 private currentSchellingRound = 1;
- constructor(address _moduleHandler) public {
+ constructor(address payable _moduleHandler) public {
/*
Install function.
@@ -147,7 +147,7 @@ contract provider is module, safeMath, announcementTypes {
else { return false; }
return true;
}
- function getUserDetails(address addr, uint256 schellingRound) public view returns (address ProviderAddress, uint256 ProviderHeight, uint256 ConnectedOn, uint256 value) {
+ function getUserDetails(address payable addr, uint256 schellingRound) public view returns (address ProviderAddress, uint256 ProviderHeight, uint256 ConnectedOn, uint256 value) {
/*
Collecting the datas of the client.
@@ -213,7 +213,7 @@ contract provider is module, safeMath, announcementTypes {
return ( ! priv && ( rate >= publicMinRate && rate <= publicMaxRate ) ) ||
( priv && ( rate >= privateMinRate && rate <= privateMaxRate ) );
}
- function createProvider(bool priv, string calldata name, string calldata website, string calldata country, string calldata info, uint8 rate, bool isForRent, address admin) isReady external {
+ function createProvider(bool priv, string calldata name, string calldata website, string calldata country, string calldata info, uint8 rate, bool isForRent, address payable admin) isReady external {
/*
Creating a provider.
During the ICO its not allowed to create provider.
@@ -270,7 +270,7 @@ contract provider is module, safeMath, announcementTypes {
}
emit EProviderOpen(msg.sender, currHeight);
}
- function setProviderDetails(address addr, string calldata website, string calldata country, string calldata info, uint8 rate, address admin) isReady external {
+ function setProviderDetails(address payable addr, string calldata website, string calldata country, string calldata info, uint8 rate, address payable admin) isReady external {
/*
Modifying the datas of the provider.
This can only be invited by the provider’s admin.
@@ -321,7 +321,7 @@ contract provider is module, safeMath, announcementTypes {
info = providers[addr].data[height].info;
create = providers[addr].data[height].create;
}
- function getProviderDetails(address addr, uint256 height) public view returns (uint8 rate, bool isForRent, uint256 clientsCount, bool priv, bool getInterest, bool valid) {
+ function getProviderDetails(address payable addr, uint256 height) public view returns (uint8 rate, bool isForRent, uint256 clientsCount, bool priv, bool getInterest, bool valid) {
/*
Asking for the datas of the provider.
In case the height is unknown then the system will use the last known height.
diff --git a/test/compilationTests/corion/publisher.sol b/test/compilationTests/corion/publisher.sol
index 6a77bc9e..48090d02 100644
--- a/test/compilationTests/corion/publisher.sol
+++ b/test/compilationTests/corion/publisher.sol
@@ -9,7 +9,7 @@ contract publisher is announcementTypes, module, safeMath {
/*
module callbacks
*/
- function transferEvent(address from, address to, uint256 value) external returns (bool success) {
+ function transferEvent(address payable from, address payable to, uint256 value) external returns (bool success) {
/*
Transaction completed. This function is available only for moduleHandler
If a transaction is carried out from or to an address which participated in the objection of an announcement, its objection purport is automatically set
@@ -54,14 +54,14 @@ contract publisher is announcementTypes, module, safeMath {
string _str;
uint256 _uint;
- address _addr;
+ address payable _addr;
}
mapping(uint256 => announcements_s) public announcements;
uint256 announcementsLength = 1;
mapping (address => uint256[]) public opponents;
- constructor(address moduleHandler) public {
+ constructor(address payable moduleHandler) public {
/*
Installation function. The installer will be registered in the admin list automatically
@@ -116,7 +116,7 @@ contract publisher is announcementTypes, module, safeMath {
return _amount * oppositeRate / 100 > weight;
}
- function newAnnouncement(announcementType Type, string calldata Announcement, string calldata Link, bool Oppositable, string calldata _str, uint256 _uint, address _addr) onlyOwner external {
+ function newAnnouncement(announcementType Type, string calldata Announcement, string calldata Link, bool Oppositable, string calldata _str, uint256 _uint, address payable _addr) onlyOwner external {
/*
New announcement. Can be called only by those in the admin list
diff --git a/test/compilationTests/corion/schelling.sol b/test/compilationTests/corion/schelling.sol
index e9288332..2a327ba0 100644
--- a/test/compilationTests/corion/schelling.sol
+++ b/test/compilationTests/corion/schelling.sol
@@ -133,13 +133,13 @@ contract schelling is module, announcementTypes, schellingVars {
/*
module callbacks
*/
- function replaceModule(address addr) external returns (bool) {
+ function replaceModule(address payable addr) external returns (bool) {
require( super.isModuleHandler(msg.sender) );
require( db.replaceOwner(addr) );
super._replaceModule(addr);
return true;
}
- function transferEvent(address from, address to, uint256 value) external returns (bool) {
+ function transferEvent(address payable from, address payable to, uint256 value) external returns (bool) {
/*
Transaction completed. This function can be called only by the ModuleHandler.
If this contract is the receiver, the amount will be added to the prize pool of the current round.
@@ -247,7 +247,7 @@ contract schelling is module, announcementTypes, schellingVars {
bytes1 public belowChar = 0x30;
schellingDB private db;
- constructor(address _moduleHandler, address _db, bool _forReplace) public {
+ constructor(address payable _moduleHandler, address _db, bool _forReplace) public {
/*
Installation function.
diff --git a/test/compilationTests/corion/token.sol b/test/compilationTests/corion/token.sol
index 6d3f1a1e..f55dc9e6 100644
--- a/test/compilationTests/corion/token.sol
+++ b/test/compilationTests/corion/token.sol
@@ -15,7 +15,7 @@ contract token is safeMath, module, announcementTypes {
/*
module callbacks
*/
- function replaceModule(address addr) external returns (bool success) {
+ function replaceModule(address payable addr) external returns (bool success) {
require( super.isModuleHandler(msg.sender) );
require( db.replaceOwner(addr) );
super._replaceModule(addr);
@@ -37,18 +37,18 @@ contract token is safeMath, module, announcementTypes {
uint8 public decimals = 6;
tokenDB public db;
- address public icoAddr;
+ address payable public icoAddr;
uint256 public transactionFeeRate = 20;
uint256 public transactionFeeRateM = 1e3;
uint256 public transactionFeeMin = 20000;
uint256 public transactionFeeMax = 5000000;
uint256 public transactionFeeBurn = 80;
- address public exchangeAddress;
+ address payable public exchangeAddress;
bool public isICO = true;
mapping(address => bool) public genesis;
- constructor(bool forReplace, address moduleHandler, address dbAddr, address icoContractAddr, address exchangeContractAddress, address[] memory genesisAddr, uint256[] memory genesisValue) public payable {
+ constructor(bool forReplace, address payable moduleHandler, address dbAddr, address payable icoContractAddr, address payable exchangeContractAddress, address payable[] memory genesisAddr, uint256[] memory genesisValue) public payable {
/*
Installation function
diff --git a/test/compilationTests/zeppelin/MultisigWallet.sol b/test/compilationTests/zeppelin/MultisigWallet.sol
index abad0a01..74a54c7f 100644
--- a/test/compilationTests/zeppelin/MultisigWallet.sol
+++ b/test/compilationTests/zeppelin/MultisigWallet.sol
@@ -32,7 +32,7 @@ contract MultisigWallet is Multisig, Shareable, DayLimit {
/**
* @dev destroys the contract sending everything to `_to`.
*/
- function destroy(address _to) onlymanyowners(keccak256(msg.data)) external {
+ function destroy(address payable _to) onlymanyowners(keccak256(msg.data)) external {
selfdestruct(_to);
}
diff --git a/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol b/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol
index 51eeb7b8..612afc25 100644
--- a/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol
+++ b/test/compilationTests/zeppelin/crowdsale/Crowdsale.sol
@@ -22,7 +22,7 @@ contract Crowdsale {
uint256 public endBlock;
// address where funds are collected
- address public wallet;
+ address payable public wallet;
// how many token units a buyer gets per wei
uint256 public rate;
@@ -40,7 +40,7 @@ contract Crowdsale {
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
- constructor(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address _wallet) public {
+ constructor(uint256 _startBlock, uint256 _endBlock, uint256 _rate, address payable _wallet) public {
require(_startBlock >= block.number);
require(_endBlock >= _startBlock);
require(_rate > 0);
diff --git a/test/compilationTests/zeppelin/crowdsale/RefundVault.sol b/test/compilationTests/zeppelin/crowdsale/RefundVault.sol
index b7db8ef2..ef1d8061 100644
--- a/test/compilationTests/zeppelin/crowdsale/RefundVault.sol
+++ b/test/compilationTests/zeppelin/crowdsale/RefundVault.sol
@@ -15,20 +15,20 @@ contract RefundVault is Ownable {
enum State { Active, Refunding, Closed }
mapping (address => uint256) public deposited;
- address public wallet;
+ address payable public wallet;
State public state;
event Closed();
event RefundsEnabled();
event Refunded(address indexed beneficiary, uint256 weiAmount);
- constructor(address _wallet) public {
+ constructor(address payable _wallet) public {
require(_wallet != address(0x0));
wallet = _wallet;
state = State.Active;
}
- function deposit(address investor) public onlyOwner payable {
+ function deposit(address payable investor) public onlyOwner payable {
require(state == State.Active);
deposited[investor] = deposited[investor].add(msg.value);
}
@@ -46,7 +46,7 @@ contract RefundVault is Ownable {
emit RefundsEnabled();
}
- function refund(address investor) public {
+ function refund(address payable investor) public {
require(state == State.Refunding);
uint256 depositedValue = deposited[investor];
deposited[investor] = 0;
diff --git a/test/compilationTests/zeppelin/lifecycle/Destructible.sol b/test/compilationTests/zeppelin/lifecycle/Destructible.sol
index 8b57924d..9b9d8223 100644
--- a/test/compilationTests/zeppelin/lifecycle/Destructible.sol
+++ b/test/compilationTests/zeppelin/lifecycle/Destructible.sol
@@ -19,7 +19,7 @@ contract Destructible is Ownable {
selfdestruct(owner);
}
- function destroyAndSend(address _recipient) public onlyOwner {
+ function destroyAndSend(address payable _recipient) public onlyOwner {
selfdestruct(_recipient);
}
}
diff --git a/test/compilationTests/zeppelin/ownership/Claimable.sol b/test/compilationTests/zeppelin/ownership/Claimable.sol
index 7778e2de..148ad535 100644
--- a/test/compilationTests/zeppelin/ownership/Claimable.sol
+++ b/test/compilationTests/zeppelin/ownership/Claimable.sol
@@ -10,7 +10,7 @@ import './Ownable.sol';
* This allows the new owner to accept the transfer.
*/
contract Claimable is Ownable {
- address public pendingOwner;
+ address payable public pendingOwner;
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
@@ -26,7 +26,7 @@ contract Claimable is Ownable {
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
- function transferOwnership(address newOwner) public onlyOwner {
+ function transferOwnership(address payable newOwner) public onlyOwner {
pendingOwner = newOwner;
}
diff --git a/test/compilationTests/zeppelin/ownership/Ownable.sol b/test/compilationTests/zeppelin/ownership/Ownable.sol
index bd175077..3c95127d 100644
--- a/test/compilationTests/zeppelin/ownership/Ownable.sol
+++ b/test/compilationTests/zeppelin/ownership/Ownable.sol
@@ -7,7 +7,7 @@ pragma solidity ^0.4.11;
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
- address public owner;
+ address payable public owner;
/**
@@ -34,7 +34,7 @@ contract Ownable {
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
- function transferOwnership(address newOwner) public onlyOwner {
+ function transferOwnership(address payable newOwner) public onlyOwner {
if (newOwner != address(0)) {
owner = newOwner;
}
diff --git a/test/compilationTests/zeppelin/payment/PullPayment.sol b/test/compilationTests/zeppelin/payment/PullPayment.sol
index bac1d019..5682d3c2 100644
--- a/test/compilationTests/zeppelin/payment/PullPayment.sol
+++ b/test/compilationTests/zeppelin/payment/PullPayment.sol
@@ -29,7 +29,7 @@ contract PullPayment {
* @dev withdraw accumulated balance, called by payee.
*/
function withdrawPayments() public {
- address payee = msg.sender;
+ address payable payee = msg.sender;
uint256 payment = payments[payee];
if (payment == 0) {
diff --git a/test/compilationTests/zeppelin/token/VestedToken.sol b/test/compilationTests/zeppelin/token/VestedToken.sol
index 2cd607bc..c9469f16 100644
--- a/test/compilationTests/zeppelin/token/VestedToken.sol
+++ b/test/compilationTests/zeppelin/token/VestedToken.sol
@@ -234,7 +234,7 @@ contract VestedToken is StandardToken, LimitedTransferToken {
}
/**
- * @dev Calculate the date when the holder can trasfer all its tokens
+ * @dev Calculate the date when the holder can transfer all its tokens
* @param holder address The address of the holder
* @return An uint256 representing the date of the last transferable tokens.
*/
diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp
index e178748f..eb274c09 100644
--- a/test/contracts/AuctionRegistrar.cpp
+++ b/test/contracts/AuctionRegistrar.cpp
@@ -40,7 +40,7 @@ namespace
{
static char const* registrarCode = R"DELIMITER(
-pragma solidity ^0.4.0;
+pragma solidity >=0.4.0 <0.6.0;
contract NameRegister {
function addr(string memory _name) public view returns (address o_owner);
@@ -66,7 +66,7 @@ contract AuctionSystem {
/// Function that is called once an auction ends.
function onAuctionEnd(string memory _name) internal;
- function bid(string memory _name, address _bidder, uint _value) internal {
+ function bid(string memory _name, address payable _bidder, uint _value) internal {
Auction storage auction = m_auctions[_name];
if (auction.endDate > 0 && now > auction.endDate)
{
@@ -91,7 +91,7 @@ contract AuctionSystem {
uint constant c_biddingTime = 7 days;
struct Auction {
- address highestBidder;
+ address payable highestBidder;
uint highestBid;
uint secondHighestBid;
uint sumOfBids;
@@ -102,7 +102,7 @@ contract AuctionSystem {
contract GlobalRegistrar is Registrar, AuctionSystem {
struct Record {
- address owner;
+ address payable owner;
address primary;
address subRegistrar;
bytes32 content;
@@ -156,7 +156,7 @@ contract GlobalRegistrar is Registrar, AuctionSystem {
modifier onlyrecordowner(string memory _name) { if (m_toRecord[_name].owner == msg.sender) _; }
- function transfer(string memory _name, address _newOwner) onlyrecordowner(_name) public {
+ function transfer(string memory _name, address payable _newOwner) onlyrecordowner(_name) public {
m_toRecord[_name].owner = _newOwner;
emit Changed(_name);
}
diff --git a/test/contracts/FixedFeeRegistrar.cpp b/test/contracts/FixedFeeRegistrar.cpp
index 78db4761..e82f389f 100644
--- a/test/contracts/FixedFeeRegistrar.cpp
+++ b/test/contracts/FixedFeeRegistrar.cpp
@@ -53,7 +53,7 @@ static char const* registrarCode = R"DELIMITER(
// @authors:
// Gav Wood <g@ethdev.com>
-pragma solidity ^0.4.0;
+pragma solidity >=0.4.0 <0.6.0;
contract Registrar {
event Changed(string indexed name);
@@ -81,7 +81,7 @@ contract FixedFeeRegistrar is Registrar {
emit Changed(_name);
}
}
- function disown(string memory _name, address _refund) onlyrecordowner(_name) public {
+ function disown(string memory _name, address payable _refund) onlyrecordowner(_name) public {
delete m_recordData[uint(keccak256(bytes(_name))) / 8];
if (!_refund.send(c_fee))
revert();
diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp
index a2e764fb..9fe02e46 100644
--- a/test/contracts/Wallet.cpp
+++ b/test/contracts/Wallet.cpp
@@ -56,7 +56,7 @@ static char const* walletCode = R"DELIMITER(
// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the
// interior is executed.
-pragma solidity ^0.4.0;
+pragma solidity >=0.4.0 <0.6.0;
contract multiowned {
@@ -375,7 +375,7 @@ contract Wallet is multisig, multiowned, daylimit {
}
// destroys the contract sending everything to `_to`.
- function kill(address _to) onlymanyowners(keccak256(msg.data)) external {
+ function kill(address payable _to) onlymanyowners(keccak256(msg.data)) external {
selfdestruct(_to);
}
diff --git a/test/externalTests.sh b/test/externalTests.sh
index f2839083..0168fb03 100755
--- a/test/externalTests.sh
+++ b/test/externalTests.sh
@@ -56,10 +56,10 @@ function test_truffle
echo "Current commit hash: `git rev-parse HEAD`"
npm install
find . -name soljson.js -exec cp "$SOLJSON" {} \;
- if [ "$name" == "Gnosis" ]; then
+ if [ "$name" == "Zeppelin" -o "$name" == "Gnosis" ]; then
echo "Replaced fixed-version pragmas..."
# Replace fixed-version pragmas in Gnosis (part of Consensys best practice)
- find contracts test -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity 0/pragma solidity ^0/'
+ find contracts test -name '*.sol' -type f -print0 | xargs -0 sed -i -e 's/pragma solidity [\^0-9\.]*/pragma solidity >=0.0/'
fi
assertsol="node_modules/truffle/build/Assert.sol"
if [ -f "$assertsol" ]
diff --git a/test/libjulia/Inliner.cpp b/test/libjulia/Inliner.cpp
index 2f5b7cff..d0ecd42f 100644
--- a/test/libjulia/Inliner.cpp
+++ b/test/libjulia/Inliner.cpp
@@ -116,6 +116,9 @@ BOOST_AUTO_TEST_CASE(negative)
BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := f() } }"), "");
BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256 { x := x } }"), "");
BOOST_CHECK_EQUAL(inlinableFunctions("{ function f() -> x:u256, y:u256 { x := 2:u256 } }"), "");
+ BOOST_CHECK_EQUAL(inlinableFunctions(
+ "{ function g() -> x:u256, y:u256 {} function f(y:u256) -> x:u256 { x,y := g() } }"), "");
+ BOOST_CHECK_EQUAL(inlinableFunctions("{ function f(y:u256) -> x:u256 { y := 2:u256 } }"), "");
}
@@ -339,5 +342,40 @@ BOOST_AUTO_TEST_CASE(pop_result)
);
}
+BOOST_AUTO_TEST_CASE(inside_condition)
+{
+ // This tests that breaking the expression inside the condition works properly.
+ BOOST_CHECK_EQUAL(
+ fullInline("{"
+ "if gt(f(mload(1)), mload(0)) {"
+ "sstore(0, 2)"
+ "}"
+ "function f(a) -> r {"
+ "a := mload(a)"
+ "r := add(a, calldatasize())"
+ "}"
+ "}", false),
+ format("{"
+ "{"
+ "let _1 := mload(0)"
+ "let f_a := mload(1)"
+ "let f_r"
+ "{"
+ "f_a := mload(f_a)"
+ "f_r := add(f_a, calldatasize())"
+ "}"
+ "if gt(f_r, _1)"
+ "{"
+ "sstore(0, 2)"
+ "}"
+ "}"
+ "function f(a) -> r"
+ "{"
+ "a := mload(a)"
+ "r := add(a, calldatasize())"
+ "}"
+ "}", false)
+ );
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp
index 39f5e620..a4394f54 100644
--- a/test/liblll/Compiler.cpp
+++ b/test/liblll/Compiler.cpp
@@ -186,6 +186,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
"60006000600060003c",
"3d",
"6000600060003e",
+ "60003f",
"600040",
"41",
"42",
@@ -291,6 +292,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
"{ (EXTCODECOPY 0 0 0 0) }",
"{ (RETURNDATASIZE) }",
"{ (RETURNDATACOPY 0 0 0) }",
+ "{ (EXTCODEHASH 0) }",
"{ (BLOCKHASH 0) }",
"{ (COINBASE) }",
"{ (TIMESTAMP) }",
@@ -356,7 +358,8 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
"{ (SELFDESTRUCT 0) }"
};
- for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
+ for (size_t i = 0; i < opcodes_bytecode.size(); i++)
+ {
vector<string> errors;
bytes code = lll::compileLLL(opcodes_lll[i], dev::test::Options::get().evmVersion(), false, &errors);
@@ -408,6 +411,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
"3c",
"3d",
"3e",
+ "3f",
"40",
"41",
"42",
@@ -546,6 +550,7 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
"{ (asm EXTCODECOPY) }",
"{ (asm RETURNDATASIZE) }",
"{ (asm RETURNDATACOPY) }",
+ "{ (asm EXTCODEHASH) }",
"{ (asm BLOCKHASH) }",
"{ (asm COINBASE) }",
"{ (asm TIMESTAMP) }",
@@ -644,7 +649,8 @@ BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
"{ (asm SELFDESTRUCT) }"
};
- for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
+ for (size_t i = 0; i < opcodes_bytecode.size(); i++)
+ {
vector<string> errors;
bytes code = lll::compileLLL(opcodes_lll[i], dev::test::Options::get().evmVersion(), false, &errors);
diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json
new file mode 100644
index 00000000..42ad33e5
--- /dev/null
+++ b/test/libsolidity/ASTJSON/address_payable.json
@@ -0,0 +1,560 @@
+{
+ "absolutePath" : "a",
+ "exportedSymbols" :
+ {
+ "C" :
+ [
+ 37
+ ]
+ },
+ "id" : 38,
+ "nodeType" : "SourceUnit",
+ "nodes" :
+ [
+ {
+ "baseContracts" : [],
+ "contractDependencies" : [],
+ "contractKind" : "contract",
+ "documentation" : null,
+ "fullyImplemented" : true,
+ "id" : 37,
+ "linearizedBaseContracts" :
+ [
+ 37
+ ],
+ "name" : "C",
+ "nodeType" : "ContractDefinition",
+ "nodes" :
+ [
+ {
+ "constant" : false,
+ "id" : 4,
+ "name" : "m",
+ "nodeType" : "VariableDeclaration",
+ "scope" : 37,
+ "src" : "17:44:1",
+ "stateVariable" : true,
+ "storageLocation" : "default",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$",
+ "typeString" : "mapping(address => address payable)"
+ },
+ "typeName" :
+ {
+ "id" : 3,
+ "keyType" :
+ {
+ "id" : 1,
+ "name" : "address",
+ "nodeType" : "ElementaryTypeName",
+ "src" : "25:7:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address",
+ "typeString" : "address"
+ }
+ },
+ "nodeType" : "Mapping",
+ "src" : "17:35:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$",
+ "typeString" : "mapping(address => address payable)"
+ },
+ "valueType" :
+ {
+ "id" : 2,
+ "name" : "address",
+ "nodeType" : "ElementaryTypeName",
+ "src" : "36:15:1",
+ "stateMutability" : "payable",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ }
+ },
+ "value" : null,
+ "visibility" : "public"
+ },
+ {
+ "body" :
+ {
+ "id" : 35,
+ "nodeType" : "Block",
+ "src" : "134:122:1",
+ "statements" :
+ [
+ {
+ "assignments" :
+ [
+ 12
+ ],
+ "declarations" :
+ [
+ {
+ "constant" : false,
+ "id" : 12,
+ "name" : "a",
+ "nodeType" : "VariableDeclaration",
+ "scope" : 35,
+ "src" : "144:17:1",
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ },
+ "typeName" :
+ {
+ "id" : 11,
+ "name" : "address",
+ "nodeType" : "ElementaryTypeName",
+ "src" : "144:15:1",
+ "stateMutability" : "payable",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "value" : null,
+ "visibility" : "internal"
+ }
+ ],
+ "id" : 16,
+ "initialValue" :
+ {
+ "argumentTypes" : null,
+ "baseExpression" :
+ {
+ "argumentTypes" : null,
+ "id" : 13,
+ "name" : "m",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 4,
+ "src" : "164:1:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$",
+ "typeString" : "mapping(address => address payable)"
+ }
+ },
+ "id" : 15,
+ "indexExpression" :
+ {
+ "argumentTypes" : null,
+ "id" : 14,
+ "name" : "arg",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 6,
+ "src" : "166:3:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "isConstant" : false,
+ "isLValue" : true,
+ "isPure" : false,
+ "lValueRequested" : false,
+ "nodeType" : "IndexAccess",
+ "src" : "164:6:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "nodeType" : "VariableDeclarationStatement",
+ "src" : "144:26:1"
+ },
+ {
+ "expression" :
+ {
+ "argumentTypes" : null,
+ "id" : 19,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : false,
+ "lValueRequested" : false,
+ "leftHandSide" :
+ {
+ "argumentTypes" : null,
+ "id" : 17,
+ "name" : "r",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 9,
+ "src" : "180:1:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "nodeType" : "Assignment",
+ "operator" : "=",
+ "rightHandSide" :
+ {
+ "argumentTypes" : null,
+ "id" : 18,
+ "name" : "arg",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 6,
+ "src" : "184:3:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "src" : "180:7:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "id" : 20,
+ "nodeType" : "ExpressionStatement",
+ "src" : "180:7:1"
+ },
+ {
+ "assignments" :
+ [
+ 22
+ ],
+ "declarations" :
+ [
+ {
+ "constant" : false,
+ "id" : 22,
+ "name" : "c",
+ "nodeType" : "VariableDeclaration",
+ "scope" : 35,
+ "src" : "197:9:1",
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address",
+ "typeString" : "address"
+ },
+ "typeName" :
+ {
+ "id" : 21,
+ "name" : "address",
+ "nodeType" : "ElementaryTypeName",
+ "src" : "197:7:1",
+ "stateMutability" : "nonpayable",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address",
+ "typeString" : "address"
+ }
+ },
+ "value" : null,
+ "visibility" : "internal"
+ }
+ ],
+ "id" : 26,
+ "initialValue" :
+ {
+ "argumentTypes" : null,
+ "arguments" :
+ [
+ {
+ "argumentTypes" : null,
+ "id" : 24,
+ "name" : "this",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 65,
+ "src" : "217:4:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_contract$_C_$37",
+ "typeString" : "contract C"
+ }
+ }
+ ],
+ "expression" :
+ {
+ "argumentTypes" :
+ [
+ {
+ "typeIdentifier" : "t_contract$_C_$37",
+ "typeString" : "contract C"
+ }
+ ],
+ "id" : 23,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "lValueRequested" : false,
+ "nodeType" : "ElementaryTypeNameExpression",
+ "src" : "209:7:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_type$_t_address_$",
+ "typeString" : "type(address)"
+ },
+ "typeName" : "address"
+ },
+ "id" : 25,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : false,
+ "kind" : "typeConversion",
+ "lValueRequested" : false,
+ "names" : [],
+ "nodeType" : "FunctionCall",
+ "src" : "209:13:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address",
+ "typeString" : "address"
+ }
+ },
+ "nodeType" : "VariableDeclarationStatement",
+ "src" : "197:25:1"
+ },
+ {
+ "expression" :
+ {
+ "argumentTypes" : null,
+ "id" : 33,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : false,
+ "lValueRequested" : false,
+ "leftHandSide" :
+ {
+ "argumentTypes" : null,
+ "baseExpression" :
+ {
+ "argumentTypes" : null,
+ "id" : 27,
+ "name" : "m",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 4,
+ "src" : "232:1:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_mapping$_t_address_$_t_address_payable_$",
+ "typeString" : "mapping(address => address payable)"
+ }
+ },
+ "id" : 29,
+ "indexExpression" :
+ {
+ "argumentTypes" : null,
+ "id" : 28,
+ "name" : "c",
+ "nodeType" : "Identifier",
+ "overloadedDeclarations" : [],
+ "referencedDeclaration" : 22,
+ "src" : "234:1:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address",
+ "typeString" : "address"
+ }
+ },
+ "isConstant" : false,
+ "isLValue" : true,
+ "isPure" : false,
+ "lValueRequested" : true,
+ "nodeType" : "IndexAccess",
+ "src" : "232:4:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "nodeType" : "Assignment",
+ "operator" : "=",
+ "rightHandSide" :
+ {
+ "argumentTypes" : null,
+ "arguments" :
+ [
+ {
+ "argumentTypes" : null,
+ "hexValue" : "30",
+ "id" : 31,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "kind" : "number",
+ "lValueRequested" : false,
+ "nodeType" : "Literal",
+ "src" : "247:1:1",
+ "subdenomination" : null,
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_rational_0_by_1",
+ "typeString" : "int_const 0"
+ },
+ "value" : "0"
+ }
+ ],
+ "expression" :
+ {
+ "argumentTypes" :
+ [
+ {
+ "typeIdentifier" : "t_rational_0_by_1",
+ "typeString" : "int_const 0"
+ }
+ ],
+ "id" : 30,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "lValueRequested" : false,
+ "nodeType" : "ElementaryTypeNameExpression",
+ "src" : "239:7:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_type$_t_address_$",
+ "typeString" : "type(address)"
+ },
+ "typeName" : "address"
+ },
+ "id" : 32,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "kind" : "typeConversion",
+ "lValueRequested" : false,
+ "names" : [],
+ "nodeType" : "FunctionCall",
+ "src" : "239:10:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "src" : "232:17:1",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "id" : 34,
+ "nodeType" : "ExpressionStatement",
+ "src" : "232:17:1"
+ }
+ ]
+ },
+ "documentation" : null,
+ "id" : 36,
+ "implemented" : true,
+ "isConstructor" : false,
+ "modifiers" : [],
+ "name" : "f",
+ "nodeType" : "FunctionDefinition",
+ "parameters" :
+ {
+ "id" : 7,
+ "nodeType" : "ParameterList",
+ "parameters" :
+ [
+ {
+ "constant" : false,
+ "id" : 6,
+ "name" : "arg",
+ "nodeType" : "VariableDeclaration",
+ "scope" : 36,
+ "src" : "78:19:1",
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ },
+ "typeName" :
+ {
+ "id" : 5,
+ "name" : "address",
+ "nodeType" : "ElementaryTypeName",
+ "src" : "78:15:1",
+ "stateMutability" : "payable",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "value" : null,
+ "visibility" : "internal"
+ }
+ ],
+ "src" : "77:21:1"
+ },
+ "returnParameters" :
+ {
+ "id" : 10,
+ "nodeType" : "ParameterList",
+ "parameters" :
+ [
+ {
+ "constant" : false,
+ "id" : 9,
+ "name" : "r",
+ "nodeType" : "VariableDeclaration",
+ "scope" : 36,
+ "src" : "115:17:1",
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ },
+ "typeName" :
+ {
+ "id" : 8,
+ "name" : "address",
+ "nodeType" : "ElementaryTypeName",
+ "src" : "115:15:1",
+ "stateMutability" : "payable",
+ "typeDescriptions" :
+ {
+ "typeIdentifier" : "t_address_payable",
+ "typeString" : "address payable"
+ }
+ },
+ "value" : null,
+ "visibility" : "internal"
+ }
+ ],
+ "src" : "114:19:1"
+ },
+ "scope" : 37,
+ "src" : "67:189:1",
+ "stateMutability" : "nonpayable",
+ "superFunction" : null,
+ "visibility" : "public"
+ }
+ ],
+ "scope" : 38,
+ "src" : "0:258:1"
+ }
+ ],
+ "src" : "0:259:1"
+}
diff --git a/test/libsolidity/ASTJSON/address_payable.sol b/test/libsolidity/ASTJSON/address_payable.sol
new file mode 100644
index 00000000..f7cc66cb
--- /dev/null
+++ b/test/libsolidity/ASTJSON/address_payable.sol
@@ -0,0 +1,11 @@
+contract C {
+ mapping(address => address payable) public m;
+ function f(address payable arg) public returns (address payable r) {
+ address payable a = m[arg];
+ r = arg;
+ address c = address(this);
+ m[c] = address(0);
+ }
+}
+
+// ----
diff --git a/test/libsolidity/ASTJSON/address_payable_legacy.json b/test/libsolidity/ASTJSON/address_payable_legacy.json
new file mode 100644
index 00000000..11a634c3
--- /dev/null
+++ b/test/libsolidity/ASTJSON/address_payable_legacy.json
@@ -0,0 +1,600 @@
+{
+ "attributes" :
+ {
+ "absolutePath" : "a",
+ "exportedSymbols" :
+ {
+ "C" :
+ [
+ 37
+ ]
+ }
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "baseContracts" :
+ [
+ null
+ ],
+ "contractDependencies" :
+ [
+ null
+ ],
+ "contractKind" : "contract",
+ "documentation" : null,
+ "fullyImplemented" : true,
+ "linearizedBaseContracts" :
+ [
+ 37
+ ],
+ "name" : "C",
+ "scope" : 38
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "constant" : false,
+ "name" : "m",
+ "scope" : 37,
+ "stateVariable" : true,
+ "storageLocation" : "default",
+ "type" : "mapping(address => address payable)",
+ "value" : null,
+ "visibility" : "public"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "type" : "mapping(address => address payable)"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "name" : "address",
+ "type" : "address"
+ },
+ "id" : 1,
+ "name" : "ElementaryTypeName",
+ "src" : "25:7:1"
+ },
+ {
+ "attributes" :
+ {
+ "name" : "address",
+ "stateMutability" : "payable",
+ "type" : "address payable"
+ },
+ "id" : 2,
+ "name" : "ElementaryTypeName",
+ "src" : "36:15:1"
+ }
+ ],
+ "id" : 3,
+ "name" : "Mapping",
+ "src" : "17:35:1"
+ }
+ ],
+ "id" : 4,
+ "name" : "VariableDeclaration",
+ "src" : "17:44:1"
+ },
+ {
+ "attributes" :
+ {
+ "documentation" : null,
+ "implemented" : true,
+ "isConstructor" : false,
+ "modifiers" :
+ [
+ null
+ ],
+ "name" : "f",
+ "scope" : 37,
+ "stateMutability" : "nonpayable",
+ "superFunction" : null,
+ "visibility" : "public"
+ },
+ "children" :
+ [
+ {
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "constant" : false,
+ "name" : "arg",
+ "scope" : 36,
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "type" : "address payable",
+ "value" : null,
+ "visibility" : "internal"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "name" : "address",
+ "stateMutability" : "payable",
+ "type" : "address payable"
+ },
+ "id" : 5,
+ "name" : "ElementaryTypeName",
+ "src" : "78:15:1"
+ }
+ ],
+ "id" : 6,
+ "name" : "VariableDeclaration",
+ "src" : "78:19:1"
+ }
+ ],
+ "id" : 7,
+ "name" : "ParameterList",
+ "src" : "77:21:1"
+ },
+ {
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "constant" : false,
+ "name" : "r",
+ "scope" : 36,
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "type" : "address payable",
+ "value" : null,
+ "visibility" : "internal"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "name" : "address",
+ "stateMutability" : "payable",
+ "type" : "address payable"
+ },
+ "id" : 8,
+ "name" : "ElementaryTypeName",
+ "src" : "115:15:1"
+ }
+ ],
+ "id" : 9,
+ "name" : "VariableDeclaration",
+ "src" : "115:17:1"
+ }
+ ],
+ "id" : 10,
+ "name" : "ParameterList",
+ "src" : "114:19:1"
+ },
+ {
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "assignments" :
+ [
+ 12
+ ]
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "constant" : false,
+ "name" : "a",
+ "scope" : 35,
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "type" : "address payable",
+ "value" : null,
+ "visibility" : "internal"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "name" : "address",
+ "stateMutability" : "payable",
+ "type" : "address payable"
+ },
+ "id" : 11,
+ "name" : "ElementaryTypeName",
+ "src" : "144:15:1"
+ }
+ ],
+ "id" : 12,
+ "name" : "VariableDeclaration",
+ "src" : "144:17:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "isConstant" : false,
+ "isLValue" : true,
+ "isPure" : false,
+ "lValueRequested" : false,
+ "type" : "address payable"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 4,
+ "type" : "mapping(address => address payable)",
+ "value" : "m"
+ },
+ "id" : 13,
+ "name" : "Identifier",
+ "src" : "164:1:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 6,
+ "type" : "address payable",
+ "value" : "arg"
+ },
+ "id" : 14,
+ "name" : "Identifier",
+ "src" : "166:3:1"
+ }
+ ],
+ "id" : 15,
+ "name" : "IndexAccess",
+ "src" : "164:6:1"
+ }
+ ],
+ "id" : 16,
+ "name" : "VariableDeclarationStatement",
+ "src" : "144:26:1"
+ },
+ {
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : false,
+ "lValueRequested" : false,
+ "operator" : "=",
+ "type" : "address payable"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 9,
+ "type" : "address payable",
+ "value" : "r"
+ },
+ "id" : 17,
+ "name" : "Identifier",
+ "src" : "180:1:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 6,
+ "type" : "address payable",
+ "value" : "arg"
+ },
+ "id" : 18,
+ "name" : "Identifier",
+ "src" : "184:3:1"
+ }
+ ],
+ "id" : 19,
+ "name" : "Assignment",
+ "src" : "180:7:1"
+ }
+ ],
+ "id" : 20,
+ "name" : "ExpressionStatement",
+ "src" : "180:7:1"
+ },
+ {
+ "attributes" :
+ {
+ "assignments" :
+ [
+ 22
+ ]
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "constant" : false,
+ "name" : "c",
+ "scope" : 35,
+ "stateVariable" : false,
+ "storageLocation" : "default",
+ "type" : "address",
+ "value" : null,
+ "visibility" : "internal"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "name" : "address",
+ "stateMutability" : "nonpayable",
+ "type" : "address"
+ },
+ "id" : 21,
+ "name" : "ElementaryTypeName",
+ "src" : "197:7:1"
+ }
+ ],
+ "id" : 22,
+ "name" : "VariableDeclaration",
+ "src" : "197:9:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : false,
+ "isStructConstructorCall" : false,
+ "lValueRequested" : false,
+ "names" :
+ [
+ null
+ ],
+ "type" : "address",
+ "type_conversion" : true
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" :
+ [
+ {
+ "typeIdentifier" : "t_contract$_C_$37",
+ "typeString" : "contract C"
+ }
+ ],
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "lValueRequested" : false,
+ "type" : "type(address)",
+ "value" : "address"
+ },
+ "id" : 23,
+ "name" : "ElementaryTypeNameExpression",
+ "src" : "209:7:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 65,
+ "type" : "contract C",
+ "value" : "this"
+ },
+ "id" : 24,
+ "name" : "Identifier",
+ "src" : "217:4:1"
+ }
+ ],
+ "id" : 25,
+ "name" : "FunctionCall",
+ "src" : "209:13:1"
+ }
+ ],
+ "id" : 26,
+ "name" : "VariableDeclarationStatement",
+ "src" : "197:25:1"
+ },
+ {
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : false,
+ "lValueRequested" : false,
+ "operator" : "=",
+ "type" : "address payable"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "isConstant" : false,
+ "isLValue" : true,
+ "isPure" : false,
+ "lValueRequested" : true,
+ "type" : "address payable"
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 4,
+ "type" : "mapping(address => address payable)",
+ "value" : "m"
+ },
+ "id" : 27,
+ "name" : "Identifier",
+ "src" : "232:1:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "overloadedDeclarations" :
+ [
+ null
+ ],
+ "referencedDeclaration" : 22,
+ "type" : "address",
+ "value" : "c"
+ },
+ "id" : 28,
+ "name" : "Identifier",
+ "src" : "234:1:1"
+ }
+ ],
+ "id" : 29,
+ "name" : "IndexAccess",
+ "src" : "232:4:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "isStructConstructorCall" : false,
+ "lValueRequested" : false,
+ "names" :
+ [
+ null
+ ],
+ "type" : "address payable",
+ "type_conversion" : true
+ },
+ "children" :
+ [
+ {
+ "attributes" :
+ {
+ "argumentTypes" :
+ [
+ {
+ "typeIdentifier" : "t_rational_0_by_1",
+ "typeString" : "int_const 0"
+ }
+ ],
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "lValueRequested" : false,
+ "type" : "type(address)",
+ "value" : "address"
+ },
+ "id" : 30,
+ "name" : "ElementaryTypeNameExpression",
+ "src" : "239:7:1"
+ },
+ {
+ "attributes" :
+ {
+ "argumentTypes" : null,
+ "hexvalue" : "30",
+ "isConstant" : false,
+ "isLValue" : false,
+ "isPure" : true,
+ "lValueRequested" : false,
+ "subdenomination" : null,
+ "token" : "number",
+ "type" : "int_const 0",
+ "value" : "0"
+ },
+ "id" : 31,
+ "name" : "Literal",
+ "src" : "247:1:1"
+ }
+ ],
+ "id" : 32,
+ "name" : "FunctionCall",
+ "src" : "239:10:1"
+ }
+ ],
+ "id" : 33,
+ "name" : "Assignment",
+ "src" : "232:17:1"
+ }
+ ],
+ "id" : 34,
+ "name" : "ExpressionStatement",
+ "src" : "232:17:1"
+ }
+ ],
+ "id" : 35,
+ "name" : "Block",
+ "src" : "134:122:1"
+ }
+ ],
+ "id" : 36,
+ "name" : "FunctionDefinition",
+ "src" : "67:189:1"
+ }
+ ],
+ "id" : 37,
+ "name" : "ContractDefinition",
+ "src" : "0:258:1"
+ }
+ ],
+ "id" : 38,
+ "name" : "SourceUnit",
+ "src" : "0:259:1"
+}
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index 736aa46c..1f6f765f 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(bool_simple)
text = R"(
contract C {
function f(bool x) public pure {
- if(x) {
+ if (x) {
assert(x);
} else {
assert(!x);
@@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE(bool_int_mixed)
contract C {
function f(bool x) public pure {
uint a;
- if(x)
+ if (x)
a = 1;
assert(!x || a > 0);
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 6be9d95b..f65c8b27 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2215,7 +2215,7 @@ BOOST_AUTO_TEST_CASE(send_ether)
char const* sourceCode = R"(
contract test {
constructor() payable public {}
- function a(address addr, uint amount) public returns (uint ret) {
+ function a(address payable addr, uint amount) public returns (uint ret) {
addr.send(amount);
return address(this).balance;
}
@@ -2233,11 +2233,11 @@ BOOST_AUTO_TEST_CASE(transfer_ether)
char const* sourceCode = R"(
contract A {
constructor() public payable {}
- function a(address addr, uint amount) public returns (uint) {
+ function a(address payable addr, uint amount) public returns (uint) {
addr.transfer(amount);
return address(this).balance;
}
- function b(address addr, uint amount) public {
+ function b(address payable addr, uint amount) public {
addr.transfer(amount);
}
}
@@ -2406,7 +2406,7 @@ BOOST_AUTO_TEST_CASE(selfdestruct)
char const* sourceCode = R"(
contract test {
constructor() public payable {}
- function a(address receiver) public returns (uint ret) {
+ function a(address payable receiver) public returns (uint ret) {
selfdestruct(receiver);
return 10;
}
@@ -3039,26 +3039,26 @@ BOOST_AUTO_TEST_CASE(gasprice)
BOOST_AUTO_TEST_CASE(blockhash)
{
- char const* sourceCode = R"(
- contract C {
- uint256 counter;
- function g() public returns (bool) { counter++; return true; }
- function f() public returns (bytes32[] memory r) {
- r = new bytes32[](259);
- for (uint i = 0; i < 259; i++)
- r[i] = blockhash(block.number - 257 + i);
- }
- }
- )";
- compileAndRun(sourceCode);
- // generate a sufficient amount of blocks
- while (blockNumber() < u256(255))
- ABI_CHECK(callContractFunction("g()"), encodeArgs(true));
-
- vector<u256> hashes;
- // currently the test only works for pre-constantinople
+ // depending on the aleth version, this test only works for pre-constantinople
if (Options::get().evmVersion() < EVMVersion::constantinople())
{
+ char const* sourceCode = R"(
+ contract C {
+ uint256 counter;
+ function g() public returns (bool) { counter++; return true; }
+ function f() public returns (bytes32[] memory r) {
+ r = new bytes32[](259);
+ for (uint i = 0; i < 259; i++)
+ r[i] = blockhash(block.number - 257 + i);
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ // generate a sufficient amount of blocks
+ while (blockNumber() < u256(255))
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(true));
+
+ vector<u256> hashes;
// ``blockhash()`` is only valid for the last 256 blocks, otherwise zero
hashes.emplace_back(0);
for (u256 i = blockNumber() - u256(255); i <= blockNumber(); i++)
@@ -3067,18 +3067,9 @@ BOOST_AUTO_TEST_CASE(blockhash)
hashes.emplace_back(0);
// future block hashes are zero
hashes.emplace_back(0);
- }
- else
- // TODO: Starting from constantinople blockhash always seems to return zero.
- // The blockhash contract introduced in EIP96 seems to break in our setup of
- // aleth (setting the constantinople fork block to zero and resetting the chain
- // to block zero before each test run). Pre-deploying the blockchain contract
- // during genesis seems to help, but currently causes problems with other tests.
- // Set the expectation to zero for now, so that this test tracks changes in this
- // behavior.
- hashes.assign(259, 0);
- ABI_CHECK(callContractFunction("f()"), encodeDyn(hashes));
+ ABI_CHECK(callContractFunction("f()"), encodeDyn(hashes));
+ }
}
BOOST_AUTO_TEST_CASE(value_complex)
@@ -7151,7 +7142,7 @@ BOOST_AUTO_TEST_CASE(failing_send)
}
contract Main {
constructor() public payable {}
- function callHelper(address _a) public returns (bool r, uint bal) {
+ function callHelper(address payable _a) public returns (bool r, uint bal) {
r = !_a.send(5);
bal = address(this).balance;
}
@@ -8838,7 +8829,7 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library)
library lib {}
contract c {
constructor() public payable {}
- function f(address x) public returns (bool) {
+ function f(address payable x) public returns (bool) {
return x.send(1);
}
function () external payable {}
@@ -10095,6 +10086,54 @@ BOOST_AUTO_TEST_CASE(cleanup_bytes_types_shortening)
ABI_CHECK(callContractFunction("f()"), encodeArgs("\xff\xff\xff\xff"));
}
+BOOST_AUTO_TEST_CASE(cleanup_address_types)
+{
+ // Checks that address types are properly cleaned before they are compared.
+ char const* sourceCode = R"(
+ contract C {
+ function f(address a) public returns (uint) {
+ if (a != 0x1234567890123456789012345678901234567890) return 1;
+ return 0;
+ }
+ function g(address payable a) public returns (uint) {
+ if (a != 0x1234567890123456789012345678901234567890) return 1;
+ return 0;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ // We input longer data on purpose.
+ ABI_CHECK(callContractFunction("f(address)", u256("0xFFFF1234567890123456789012345678901234567890")), encodeArgs(0));
+ ABI_CHECK(callContractFunction("g(address)", u256("0xFFFF1234567890123456789012345678901234567890")), encodeArgs(0));
+}
+
+BOOST_AUTO_TEST_CASE(cleanup_address_types_shortening)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function f() public pure returns (address r) {
+ bytes21 x = 0x1122334455667788990011223344556677889900ff;
+ bytes20 y;
+ assembly { y := x }
+ address z = address(y);
+ assembly { r := z }
+ require(z == 0x1122334455667788990011223344556677889900);
+ }
+ function g() public pure returns (address payable r) {
+ bytes21 x = 0x1122334455667788990011223344556677889900ff;
+ bytes20 y;
+ assembly { y := x }
+ address payable z = address(y);
+ assembly { r := z }
+ require(z == 0x1122334455667788990011223344556677889900);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(u256("0x1122334455667788990011223344556677889900")));
+ ABI_CHECK(callContractFunction("g()"), encodeArgs(u256("0x1122334455667788990011223344556677889900")));
+}
+
BOOST_AUTO_TEST_CASE(skip_dynamic_types)
{
// The EVM cannot provide access to dynamically-sized return values, so we have to skip them.
@@ -12446,7 +12485,7 @@ BOOST_AUTO_TEST_CASE(interface_contract)
}
contract C {
- function f(address _interfaceAddress) public returns (bool) {
+ function f(address payable _interfaceAddress) public returns (bool) {
I i = I(_interfaceAddress);
return i.f();
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index af8465fc..640bf4d0 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -396,7 +396,7 @@ BOOST_AUTO_TEST_CASE(returndatasize_as_variable)
{Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"}
});
if (!dev::test::Options::get().evmVersion().supportsReturndata())
- expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible")));
+ expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible VMs.")));
CHECK_ALLOW_MULTI(text, expectations);
}
@@ -407,9 +407,24 @@ BOOST_AUTO_TEST_CASE(create2_as_variable)
)";
// This needs special treatment, because the message mentions the EVM version,
// so cannot be run via isoltest.
+ vector<pair<Error::Type, std::string>> expectations(vector<pair<Error::Type, std::string>>{
+ {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"}
+ });
+ if (!dev::test::Options::get().evmVersion().hasCreate2())
+ expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"create2\" instruction is only available for Constantinople-compatible VMs.")));
+ CHECK_ALLOW_MULTI(text, expectations);
+}
+
+BOOST_AUTO_TEST_CASE(extcodehash_as_variable)
+{
+ char const* text = R"(
+ contract c { function f() public view { uint extcodehash; extcodehash; assembly { pop(extcodehash(0)) } }}
+ )";
+ // This needs special treatment, because the message mentions the EVM version,
+ // so cannot be run via isoltest.
CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{
{Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"},
- {Error::Type::Warning, "The \"create2\" instruction is not supported by the VM version"},
+ {Error::Type::Warning, "The \"extcodehash\" instruction is not supported by the VM version"},
}));
}
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index 1c80e82e..f925d36e 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -352,7 +352,7 @@ BOOST_AUTO_TEST_CASE(incorrect_storage_access_bug)
mapping(uint => uint) data;
function f() public returns (uint)
{
- if(data[now] == 0)
+ if (data[now] == 0)
data[uint(-7)] = 5;
return data[now];
}
diff --git a/test/libsolidity/SolidityScanner.cpp b/test/libsolidity/SolidityScanner.cpp
index 3a210f94..93db236b 100644
--- a/test/libsolidity/SolidityScanner.cpp
+++ b/test/libsolidity/SolidityScanner.cpp
@@ -105,6 +105,11 @@ BOOST_AUTO_TEST_CASE(hex_numbers)
BOOST_CHECK_EQUAL(scanner.currentLiteral(), "0x765432536763762734623472346");
BOOST_CHECK_EQUAL(scanner.next(), Token::Semicolon);
BOOST_CHECK_EQUAL(scanner.next(), Token::EOS);
+ scanner.reset(CharStream("0x1234"), "");
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Number);
+ BOOST_CHECK_EQUAL(scanner.currentLiteral(), "0x1234");
+ scanner.reset(CharStream("0X1234"), "");
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::Illegal);
}
BOOST_AUTO_TEST_CASE(octal_numbers)
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 3aa1dc24..1570a9d2 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -225,6 +225,71 @@ BOOST_AUTO_TEST_CASE(smoke_test)
BOOST_CHECK(containsAtMostWarnings(result));
}
+BOOST_AUTO_TEST_CASE(optimizer_enabled_not_boolean)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "optimizer": {
+ "enabled": "wrong"
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "The \"enabled\" setting must be a boolean."));
+}
+
+BOOST_AUTO_TEST_CASE(optimizer_runs_not_a_number)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "optimizer": {
+ "enabled": true,
+ "runs": "not a number"
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "The \"runs\" setting must be an unsigned number."));
+}
+
+BOOST_AUTO_TEST_CASE(optimizer_runs_not_an_unsigned_number)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "optimizer": {
+ "enabled": true,
+ "runs": -1
+ }
+ },
+ "sources": {
+ "empty": {
+ "content": ""
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsError(result, "JSONError", "The \"runs\" setting must be an unsigned number."));
+}
+
BOOST_AUTO_TEST_CASE(basic_compilation)
{
char const* input = R"(
@@ -640,7 +705,7 @@ BOOST_AUTO_TEST_CASE(libraries_invalid_entry)
}
)";
Json::Value result = compile(input);
- BOOST_CHECK(containsError(result, "JSONError", "library entry is not a JSON object."));
+ BOOST_CHECK(containsError(result, "JSONError", "Library entry is not a JSON object."));
}
BOOST_AUTO_TEST_CASE(libraries_invalid_hex)
diff --git a/test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol b/test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol
new file mode 100644
index 00000000..fd8f3078
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol
@@ -0,0 +1,15 @@
+contract C {
+ function a() public pure returns(int[0][500] memory) {}
+ function b() public pure returns(uint[0][500] memory) {}
+ function c() public pure returns(byte[0][500] memory) {}
+ function d() public pure returns(bytes32[0][500] memory) {}
+ function e() public pure returns(bytes[0][500] memory) {}
+ function e() public pure returns(string[0][500] memory) {}
+}
+// ----
+// TypeError: (52-53): Array with zero length specified.
+// TypeError: (111-112): Array with zero length specified.
+// TypeError: (170-171): Array with zero length specified.
+// TypeError: (232-233): Array with zero length specified.
+// TypeError: (292-293): Array with zero length specified.
+// TypeError: (353-354): Array with zero length specified.
diff --git a/test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol b/test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol
new file mode 100644
index 00000000..b38939e3
--- /dev/null
+++ b/test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol
@@ -0,0 +1,15 @@
+contract C {
+ int[0] a;
+ uint[0] b;
+ byte[0] c;
+ bytes32[0] d;
+ bytes[0] e;
+ string[0] f;
+}
+// ----
+// TypeError: (19-20): Array with zero length specified.
+// TypeError: (32-33): Array with zero length specified.
+// TypeError: (45-46): Array with zero length specified.
+// TypeError: (61-62): Array with zero length specified.
+// TypeError: (75-76): Array with zero length specified.
+// TypeError: (90-91): Array with zero length specified.
diff --git a/test/libsolidity/syntaxTests/array/length/parentheses.sol b/test/libsolidity/syntaxTests/array/length/parentheses.sol
index 40f55ad6..8dbcc0a4 100644
--- a/test/libsolidity/syntaxTests/array/length/parentheses.sol
+++ b/test/libsolidity/syntaxTests/array/length/parentheses.sol
@@ -21,5 +21,5 @@ contract C {
uint[((2) + 1) + 1] a12;
uint[(2 + 1) + ((1))] a13;
uint[(((2) + 1)) + (((1)))] a14;
- uint[((((2) + 1)) + (((1))))%1] a15;
+ uint[((((3) + 1)) + (((1))))%2] a15;
}
diff --git a/test/libsolidity/syntaxTests/conversion/allowed_conversion_to_bytes_array.sol b/test/libsolidity/syntaxTests/conversion/allowed_conversion_to_bytes_array.sol
new file mode 100644
index 00000000..78c40e53
--- /dev/null
+++ b/test/libsolidity/syntaxTests/conversion/allowed_conversion_to_bytes_array.sol
@@ -0,0 +1,9 @@
+contract C {
+ bytes a;
+ bytes b;
+ function f() public view {
+ bytes storage c = a;
+ bytes memory d = b;
+ d = bytes(c);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/conversion/allowed_conversion_to_string.sol b/test/libsolidity/syntaxTests/conversion/allowed_conversion_to_string.sol
new file mode 100644
index 00000000..f7e96f35
--- /dev/null
+++ b/test/libsolidity/syntaxTests/conversion/allowed_conversion_to_string.sol
@@ -0,0 +1,9 @@
+contract C {
+ string a;
+ string b;
+ function f() public view {
+ string storage c = a;
+ string memory d = b;
+ d = string(c);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_storage_array_ref.sol b/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_storage_array_ref.sol
new file mode 100644
index 00000000..458adda6
--- /dev/null
+++ b/test/libsolidity/syntaxTests/conversion/explicit_conversion_from_storage_array_ref.sol
@@ -0,0 +1,10 @@
+contract C {
+ int[10] x;
+ function f() public view {
+ int[](x);
+ int(x);
+ }
+}
+// ----
+// TypeError: (55-63): Explicit type conversion not allowed from "int256[10] storage ref" to "int256[] storage pointer".
+// TypeError: (67-73): Explicit type conversion not allowed from "int256[10] storage ref" to "int256".
diff --git a/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_storage_array_ref.sol b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_storage_array_ref.sol
new file mode 100644
index 00000000..31e298d0
--- /dev/null
+++ b/test/libsolidity/syntaxTests/conversion/implicit_conversion_from_storage_array_ref.sol
@@ -0,0 +1,7 @@
+contract C {
+ int[10] x;
+ int[] y;
+ function f() public {
+ y = x;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer1.sol b/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer1.sol
new file mode 100644
index 00000000..3aa59612
--- /dev/null
+++ b/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer1.sol
@@ -0,0 +1,10 @@
+contract C {
+ uint[] a;
+ uint[] b;
+ function f() public view {
+ uint[] storage c = a;
+ uint[] storage d = b;
+ d = uint[](c);
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer2.sol b/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer2.sol
new file mode 100644
index 00000000..060c9707
--- /dev/null
+++ b/test/libsolidity/syntaxTests/conversion/not_allowed_conversion_to_int_array_pointer2.sol
@@ -0,0 +1,10 @@
+contract C {
+ uint[] a;
+ uint[] b;
+ function f() public view {
+ uint[] storage c = a;
+ uint[] memory d = b;
+ d = uint[](c);
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/dataLocations/memory_storage_data_location.sol b/test/libsolidity/syntaxTests/dataLocations/memory_storage_data_location.sol
new file mode 100644
index 00000000..a441b540
--- /dev/null
+++ b/test/libsolidity/syntaxTests/dataLocations/memory_storage_data_location.sol
@@ -0,0 +1,12 @@
+contract C {
+ int[] x;
+ function f() public {
+ int[] storage a = x;
+ int[] memory b;
+ a = b;
+ a = int[](b);
+ }
+}
+// ----
+// TypeError: (93-94): Type int256[] memory is not implicitly convertible to expected type int256[] storage pointer.
+// TypeError: (102-110): Type int256[] memory is not implicitly convertible to expected type int256[] storage pointer.
diff --git a/test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol b/test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol
new file mode 100644
index 00000000..adffb14b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/functionTypes/external_function_type_to_address_payable.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f() public view returns (address payable) {
+ return address(this.f);
+ }
+}
+// ----
+// TypeError: (85-100): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/multiline_comments.sol b/test/libsolidity/syntaxTests/multiline_comments.sol
new file mode 100644
index 00000000..480fde6c
--- /dev/null
+++ b/test/libsolidity/syntaxTests/multiline_comments.sol
@@ -0,0 +1,13 @@
+/*
+ * This is a multi-line comment
+ * it should create no problems
+ *
+*/
+
+contract test {
+ /*
+ * this is another multi-line comment
+ *
+ */
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/413_address_methods.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/413_address_methods.sol
index b63d2a55..ad57224c 100644
--- a/test/libsolidity/syntaxTests/nameAndTypeResolution/413_address_methods.sol
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/413_address_methods.sol
@@ -1,6 +1,6 @@
contract C {
function f() public {
- address addr;
+ address payable addr;
uint balance = addr.balance;
(bool callSuc,) = addr.call("");
(bool delegatecallSuc,) = addr.delegatecall("");
diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/535_address_overload_resolution.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/535_address_overload_resolution.sol
index 157ea36b..01b7b294 100644
--- a/test/libsolidity/syntaxTests/nameAndTypeResolution/535_address_overload_resolution.sol
+++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/535_address_overload_resolution.sol
@@ -6,6 +6,8 @@ contract C {
function transfer(uint amount) public {
address(this).transfer(amount); // to avoid pureness warning
}
+ function() payable external {
+ }
}
contract D {
function f() public {
diff --git a/test/libsolidity/syntaxTests/parsing/address_constant_payable.sol b/test/libsolidity/syntaxTests/parsing/address_constant_payable.sol
new file mode 100644
index 00000000..d98f4ae3
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_constant_payable.sol
@@ -0,0 +1,5 @@
+contract C {
+ address constant payable b = address(0);
+}
+// ----
+// ParserError: (34-41): Expected identifier but got 'payable'
diff --git a/test/libsolidity/syntaxTests/parsing/address_function_arguments_and_returns.sol b/test/libsolidity/syntaxTests/parsing/address_function_arguments_and_returns.sol
new file mode 100644
index 00000000..c377600a
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_function_arguments_and_returns.sol
@@ -0,0 +1,4 @@
+contract C {
+ function f(address) public pure returns (address) {}
+ function g(address payable) public pure returns (address payable) {}
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_in_struct.sol b/test/libsolidity/syntaxTests/parsing/address_in_struct.sol
new file mode 100644
index 00000000..68049b50
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_in_struct.sol
@@ -0,0 +1,6 @@
+contract C {
+ struct S {
+ address payable a;
+ address b;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_invalid_state_mutability.sol b/test/libsolidity/syntaxTests/parsing/address_invalid_state_mutability.sol
new file mode 100644
index 00000000..606f5cd0
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_invalid_state_mutability.sol
@@ -0,0 +1,26 @@
+contract C {
+ address view m_a;
+ address pure m_b;
+ address view[] m_c;
+ mapping(uint => address view) m_d;
+ function f() public pure {
+ address view a;
+ address pure b;
+ a; b;
+ }
+ function g(address view) public pure {}
+ function h(address pure) public pure {}
+ function i() public pure returns (address view) {}
+ function j() public pure returns (address pure) {}
+}
+// ----
+// TypeError: (14-26): Address types can only be payable or non-payable.
+// TypeError: (33-45): Address types can only be payable or non-payable.
+// TypeError: (52-64): Address types can only be payable or non-payable.
+// TypeError: (89-101): Address types can only be payable or non-payable.
+// TypeError: (195-207): Address types can only be payable or non-payable.
+// TypeError: (236-248): Address types can only be payable or non-payable.
+// TypeError: (300-312): Address types can only be payable or non-payable.
+// TypeError: (352-364): Address types can only be payable or non-payable.
+// TypeError: (138-150): Address types can only be payable or non-payable.
+// TypeError: (156-168): Address types can only be payable or non-payable.
diff --git a/test/libsolidity/syntaxTests/parsing/address_nonpayable.sol b/test/libsolidity/syntaxTests/parsing/address_nonpayable.sol
new file mode 100644
index 00000000..fea67138
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_nonpayable.sol
@@ -0,0 +1,7 @@
+contract C {
+ address a;
+ function f(address b) public pure returns (address c) {
+ address d = b;
+ return d;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable.sol b/test/libsolidity/syntaxTests/parsing/address_payable.sol
new file mode 100644
index 00000000..c29ae1b7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable.sol
@@ -0,0 +1,7 @@
+contract C {
+ address payable a;
+ function f(address payable b) public pure returns (address payable c) {
+ address payable d = b;
+ return d;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_constant.sol b/test/libsolidity/syntaxTests/parsing/address_payable_constant.sol
new file mode 100644
index 00000000..154bfb54
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_constant.sol
@@ -0,0 +1,3 @@
+contract C {
+ address payable constant a = address(0);
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_conversion.sol b/test/libsolidity/syntaxTests/parsing/address_payable_conversion.sol
new file mode 100644
index 00000000..bf073a52
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_conversion.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f() public pure {
+ address payable a = address payable(this);
+ }
+}
+// ----
+// ParserError: (80-87): Expected ';' but got 'payable'
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_function_type.sol b/test/libsolidity/syntaxTests/parsing/address_payable_function_type.sol
new file mode 100644
index 00000000..234b528a
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_function_type.sol
@@ -0,0 +1,6 @@
+contract C {
+ function (address payable) view internal returns (address payable) f;
+ function g(function (address payable) payable external returns (address payable)) public payable returns (function (address payable) payable external returns (address payable)) {
+ function (address payable) payable external returns (address payable) h; h;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_library.sol b/test/libsolidity/syntaxTests/parsing/address_payable_library.sol
new file mode 100644
index 00000000..33787d33
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_library.sol
@@ -0,0 +1,5 @@
+library L {
+}
+contract C {
+ using L for address payable;
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_local.sol b/test/libsolidity/syntaxTests/parsing/address_payable_local.sol
new file mode 100644
index 00000000..544f7c21
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_local.sol
@@ -0,0 +1,11 @@
+contract C {
+ mapping(uint => address payable) m;
+ mapping(uint => address payable[]) n;
+ function f() public view {
+ address payable a;
+ address payable[] memory b;
+ mapping(uint => address payable) storage c = m;
+ mapping(uint => address payable[]) storage d = n;
+ a; b; c; d;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_state_variable.sol b/test/libsolidity/syntaxTests/parsing/address_payable_state_variable.sol
new file mode 100644
index 00000000..12c2468d
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_state_variable.sol
@@ -0,0 +1,8 @@
+contract C {
+ address payable a;
+ address payable public b;
+ address payable[] c;
+ address payable[] public d;
+ mapping(uint => address payable) e;
+ mapping(uint => address payable[]) f;
+}
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_struct.sol b/test/libsolidity/syntaxTests/parsing/address_payable_struct.sol
new file mode 100644
index 00000000..6c281bc7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_struct.sol
@@ -0,0 +1,8 @@
+contract C {
+ struct S {
+ address payable a;
+ address payable[] b;
+ mapping(uint => address payable) c;
+ mapping(uint => address payable[]) d;
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/parsing/address_payable_type_expression.sol b/test/libsolidity/syntaxTests/parsing/address_payable_type_expression.sol
new file mode 100644
index 00000000..394b39c0
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_payable_type_expression.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f() public pure {
+ address payable;
+ }
+}
+// ----
+// ParserError: (67-68): Expected identifier but got ';'
diff --git a/test/libsolidity/syntaxTests/parsing/address_public_payable_error.sol b/test/libsolidity/syntaxTests/parsing/address_public_payable_error.sol
new file mode 100644
index 00000000..0acf5e4b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/address_public_payable_error.sol
@@ -0,0 +1,5 @@
+contract C {
+ address public payable a;
+}
+// ----
+// ParserError: (32-39): Expected identifier but got 'payable'
diff --git a/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol b/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol
index 9181222e..9adf6f12 100644
--- a/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol
+++ b/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol
@@ -1,6 +1,6 @@
contract c {
uint[10] a;
uint[] a2;
- struct x { uint[2**20] b; y[0] c; }
+ struct x { uint[2**20] b; y[1] c; }
struct y { uint d; mapping(uint=>x)[] e; }
}
diff --git a/test/libsolidity/syntaxTests/parsing/elemantary_non_address_payable_state_variable.sol b/test/libsolidity/syntaxTests/parsing/elemantary_non_address_payable_state_variable.sol
new file mode 100644
index 00000000..41b2762b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/elemantary_non_address_payable_state_variable.sol
@@ -0,0 +1,29 @@
+contract C {
+ bool payable a;
+ string payable b;
+ int payable c;
+ int256 payable d;
+ uint payable e;
+ uint256 payable f;
+ byte payable g;
+ bytes payable h;
+ bytes32 payable i;
+ fixed payable j;
+ fixed80x80 payable k;
+ ufixed payable l;
+ ufixed80x80 payable m;
+}
+// ----
+// ParserError: (22-29): State mutability can only be specified for address types.
+// ParserError: (44-51): State mutability can only be specified for address types.
+// ParserError: (63-70): State mutability can only be specified for address types.
+// ParserError: (85-92): State mutability can only be specified for address types.
+// ParserError: (105-112): State mutability can only be specified for address types.
+// ParserError: (128-135): State mutability can only be specified for address types.
+// ParserError: (148-155): State mutability can only be specified for address types.
+// ParserError: (169-176): State mutability can only be specified for address types.
+// ParserError: (192-199): State mutability can only be specified for address types.
+// ParserError: (213-220): State mutability can only be specified for address types.
+// ParserError: (239-246): State mutability can only be specified for address types.
+// ParserError: (261-268): State mutability can only be specified for address types.
+// ParserError: (288-295): State mutability can only be specified for address types.
diff --git a/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_argument.sol b/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_argument.sol
new file mode 100644
index 00000000..9cb0fb4f
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_argument.sol
@@ -0,0 +1,29 @@
+contract C {
+ function a(bool payable) public pure {}
+ function b(string payable) public pure {}
+ function c(int payable) public pure {}
+ function d(int256 payable) public pure {}
+ function e(uint payable) public pure {}
+ function f(uint256 payable) public pure {}
+ function g(byte payable) public pure {}
+ function h(bytes payable) public pure {}
+ function i(bytes32 payable) public pure {}
+ function j(fixed payable) public pure {}
+ function k(fixed80x80 payable) public pure {}
+ function l(ufixed payable) public pure {}
+ function m(ufixed80x80 payable) public pure {}
+}
+// ----
+// ParserError: (33-40): State mutability can only be specified for address types.
+// ParserError: (79-86): State mutability can only be specified for address types.
+// ParserError: (122-129): State mutability can only be specified for address types.
+// ParserError: (168-175): State mutability can only be specified for address types.
+// ParserError: (212-219): State mutability can only be specified for address types.
+// ParserError: (259-266): State mutability can only be specified for address types.
+// ParserError: (303-310): State mutability can only be specified for address types.
+// ParserError: (348-355): State mutability can only be specified for address types.
+// ParserError: (395-402): State mutability can only be specified for address types.
+// ParserError: (440-447): State mutability can only be specified for address types.
+// ParserError: (490-497): State mutability can only be specified for address types.
+// ParserError: (536-543): State mutability can only be specified for address types.
+// ParserError: (587-594): State mutability can only be specified for address types.
diff --git a/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_local.sol b/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_local.sol
new file mode 100644
index 00000000..3d47f1c7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_local.sol
@@ -0,0 +1,31 @@
+contract C {
+ function f() public pure {
+ bool payable a;
+ string payable b;
+ int payable c;
+ int256 payable d;
+ uint payable e;
+ uint256 payable f;
+ byte payable g;
+ bytes payable h;
+ bytes32 payable i;
+ fixed payable j;
+ fixed80x80 payable k;
+ ufixed payable l;
+ ufixed80x80 payable m;
+ }
+}
+// ----
+// ParserError: (57-64): State mutability can only be specified for address types.
+// ParserError: (83-90): State mutability can only be specified for address types.
+// ParserError: (106-113): State mutability can only be specified for address types.
+// ParserError: (132-139): State mutability can only be specified for address types.
+// ParserError: (156-163): State mutability can only be specified for address types.
+// ParserError: (183-190): State mutability can only be specified for address types.
+// ParserError: (207-214): State mutability can only be specified for address types.
+// ParserError: (232-239): State mutability can only be specified for address types.
+// ParserError: (259-266): State mutability can only be specified for address types.
+// ParserError: (284-291): State mutability can only be specified for address types.
+// ParserError: (314-321): State mutability can only be specified for address types.
+// ParserError: (340-347): State mutability can only be specified for address types.
+// ParserError: (371-378): State mutability can only be specified for address types.
diff --git a/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_return.sol b/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_return.sol
new file mode 100644
index 00000000..fc7a3c25
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/elementary_non_address_payable_return.sol
@@ -0,0 +1,29 @@
+contract C {
+ function a() public pure returns (bool payable) {}
+ function b() public pure returns (string payable) {}
+ function c() public pure returns (int payable) {}
+ function d() public pure returns (int256 payable) {}
+ function e() public pure returns (uint payable) {}
+ function f() public pure returns (uint256 payable) {}
+ function g() public pure returns (byte payable) {}
+ function h() public pure returns (bytes payable) {}
+ function i() public pure returns (bytes32 payable) {}
+ function j() public pure returns (fixed payable) {}
+ function k() public pure returns (fixed80x80 payable) {}
+ function l() public pure returns (ufixed payable) {}
+ function m() public pure returns (ufixed80x80 payable) {}
+}
+// ----
+// ParserError: (56-63): State mutability can only be specified for address types.
+// ParserError: (113-120): State mutability can only be specified for address types.
+// ParserError: (167-174): State mutability can only be specified for address types.
+// ParserError: (224-231): State mutability can only be specified for address types.
+// ParserError: (279-286): State mutability can only be specified for address types.
+// ParserError: (337-344): State mutability can only be specified for address types.
+// ParserError: (392-399): State mutability can only be specified for address types.
+// ParserError: (448-455): State mutability can only be specified for address types.
+// ParserError: (506-513): State mutability can only be specified for address types.
+// ParserError: (562-569): State mutability can only be specified for address types.
+// ParserError: (623-630): State mutability can only be specified for address types.
+// ParserError: (680-687): State mutability can only be specified for address types.
+// ParserError: (742-749): State mutability can only be specified for address types.
diff --git a/test/libsolidity/syntaxTests/parsing/mapping_from_address_payable.sol b/test/libsolidity/syntaxTests/parsing/mapping_from_address_payable.sol
new file mode 100644
index 00000000..7e6f98d7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/mapping_from_address_payable.sol
@@ -0,0 +1,5 @@
+contract C {
+ mapping(address payable => uint) m;
+}
+// ----
+// ParserError: (33-40): Expected '=>' but got 'payable'
diff --git a/test/libsolidity/syntaxTests/parsing/new_address_payable.sol b/test/libsolidity/syntaxTests/parsing/new_address_payable.sol
new file mode 100644
index 00000000..a52001db
--- /dev/null
+++ b/test/libsolidity/syntaxTests/parsing/new_address_payable.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f() public pure returns(address payable[] memory m) {
+ m = new address payable[](10);
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/parsing/payable_accessor.sol b/test/libsolidity/syntaxTests/parsing/payable_accessor.sol
index 6504004b..0bc85784 100644
--- a/test/libsolidity/syntaxTests/parsing/payable_accessor.sol
+++ b/test/libsolidity/syntaxTests/parsing/payable_accessor.sol
@@ -2,4 +2,4 @@ contract test {
uint payable x;
}
// ----
-// ParserError: (22-29): Expected identifier but got 'payable'
+// ParserError: (22-29): State mutability can only be specified for address types.
diff --git a/test/libsolidity/syntaxTests/string/string_escapes.sol b/test/libsolidity/syntaxTests/string/string_escapes.sol
new file mode 100644
index 00000000..51b90d73
--- /dev/null
+++ b/test/libsolidity/syntaxTests/string/string_escapes.sol
@@ -0,0 +1,7 @@
+contract test {
+ function f() public pure returns (bytes32) {
+ bytes32 escapeCharacters = "\t\b\n\r\f\'\"\\\b";
+ return escapeCharacters;
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/string/string_new_line.sol b/test/libsolidity/syntaxTests/string/string_new_line.sol
new file mode 100644
index 00000000..da2240f7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/string/string_new_line.sol
@@ -0,0 +1,9 @@
+contract test {
+ function f() public pure returns (bytes32) {
+ bytes32 escapeCharacters = "This a test
+ ";
+ return escapeCharacters;
+ }
+}
+// ----
+// ParserError: (100-112): Expected primary expression.
diff --git a/test/libsolidity/syntaxTests/string/string_terminated_by_backslash.sol b/test/libsolidity/syntaxTests/string/string_terminated_by_backslash.sol
new file mode 100644
index 00000000..3eaba6af
--- /dev/null
+++ b/test/libsolidity/syntaxTests/string/string_terminated_by_backslash.sol
@@ -0,0 +1,8 @@
+contract test {
+ function f() public pure returns (bytes32) {
+ bytes32 escapeCharacters = "text \";
+ return escapeCharacters;
+ }
+}
+// ----
+// ParserError: (100-109): Expected primary expression. \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/string/string_unterminated.sol b/test/libsolidity/syntaxTests/string/string_unterminated.sol
new file mode 100644
index 00000000..3291781e
--- /dev/null
+++ b/test/libsolidity/syntaxTests/string/string_unterminated.sol
@@ -0,0 +1,7 @@
+contract test {
+ function f() public pure returns (bytes32) {
+ bytes32 escapeCharacters = "This a test
+ }
+}
+// ----
+// ParserError: (100-112): Expected primary expression. \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/string/string_unterminated_no_new_line.sol b/test/libsolidity/syntaxTests/string/string_unterminated_no_new_line.sol
new file mode 100644
index 00000000..e7be50d2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/string/string_unterminated_no_new_line.sol
@@ -0,0 +1,4 @@
+contract test {
+ function f() pure public { "abc\
+// ----
+// ParserError: (47-53): Expected primary expression. \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/types/address/address_abi_decode.sol b/test/libsolidity/syntaxTests/types/address/address_abi_decode.sol
new file mode 100644
index 00000000..7be61ad2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_abi_decode.sol
@@ -0,0 +1,6 @@
+contract C {
+ function f(bytes memory b) public pure returns (address payable) {
+ (address payable c) = abi.decode(b, (address));
+ return c;
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/types/address/address_constant.sol b/test/libsolidity/syntaxTests/types/address/address_constant.sol
new file mode 100644
index 00000000..0b1af991
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_constant.sol
@@ -0,0 +1,7 @@
+contract C {
+ address constant a = address(0);
+ address payable constant b = address(0);
+ function f() public pure returns (address, address) {
+ return (a,b);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol b/test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol
new file mode 100644
index 00000000..da17ae33
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_constant_assignment.sol
@@ -0,0 +1,11 @@
+contract C {
+ address constant a = address(0);
+ address payable constant b = address(0);
+ function f() public {
+ a = address(0);
+ b = address(0);
+ }
+}
+// ----
+// TypeError: (129-130): Cannot assign to a constant variable.
+// TypeError: (153-154): Cannot assign to a constant variable.
diff --git a/test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol b/test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol
new file mode 100644
index 00000000..9a5b2abb
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_in_struct_fail.sol
@@ -0,0 +1,11 @@
+contract A {
+ struct S {
+ address payable a;
+ }
+ S s;
+ function f() public {
+ s.a = address(this);
+ }
+}
+// ----
+// TypeError: (110-123): Type address is not implicitly convertible to expected type address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol b/test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol
new file mode 100644
index 00000000..5519f0ef
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_in_struct_fine.sol
@@ -0,0 +1,20 @@
+contract A {
+ struct S {
+ address a;
+ }
+ S s;
+ function f() public {
+ s.a = address(this);
+ }
+}
+contract B {
+ struct S {
+ address payable a;
+ }
+ S s;
+ function f() public {
+ s.a = address(this);
+ }
+ function() external payable {
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/types/address_members_in_contract.sol b/test/libsolidity/syntaxTests/types/address/address_members_in_contract.sol
index eafc8268..eafc8268 100644
--- a/test/libsolidity/syntaxTests/types/address_members_in_contract.sol
+++ b/test/libsolidity/syntaxTests/types/address/address_members_in_contract.sol
diff --git a/test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol b/test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol
new file mode 100644
index 00000000..cc680ff3
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_nonpayable_selfdestruct.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f(address a) public {
+ selfdestruct(a);
+ }
+}
+// ----
+// TypeError: (69-70): Invalid type for argument in function call. Invalid implicit conversion from address to address payable requested.
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol b/test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol
new file mode 100644
index 00000000..875532c4
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_external_overload.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f(address) external pure {}
+ function f(address payable) external pure {}
+
+}
+// ----
+// TypeError: (58-102): Function overload clash during conversion to external types for arguments.
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol
new file mode 100644
index 00000000..65600544
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_nonpayable.sol
@@ -0,0 +1,10 @@
+contract C {
+ function f(address payable) internal pure {}
+ function f(address) internal pure returns (uint) {}
+ function g() internal pure {
+ address a = address(0);
+ uint b = f(a); // TODO: should this be valid?
+ b;
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol
new file mode 100644
index 00000000..84142a31
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_internal_overload_payable.sol
@@ -0,0 +1,10 @@
+contract C {
+ function f(address payable) internal pure {}
+ function f(address) internal pure {}
+ function g() internal pure {
+ address payable a = address(0);
+ f(a);
+ }
+}
+// ----
+// TypeError: (184-185): No unique declaration found after argument-dependent lookup.
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol b/test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol
new file mode 100644
index 00000000..ec58170b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_memory_array_conversion.sol
@@ -0,0 +1,11 @@
+contract C {
+ function f() public pure {
+ address payable[] memory a = new address payable[](4);
+ address[] memory b = new address[](4);
+ a = b;
+ b = a;
+ }
+}
+// ----
+// TypeError: (166-167): Type address[] memory is not implicitly convertible to expected type address payable[] memory.
+// TypeError: (181-182): Type address payable[] memory is not implicitly convertible to expected type address[] memory.
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol b/test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol
new file mode 100644
index 00000000..839abc26
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_public_overload.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f(address) public pure {}
+ function f(address payable) public pure {}
+
+}
+// ----
+// TypeError: (56-98): Function overload clash during conversion to external types for arguments.
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol b/test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol
new file mode 100644
index 00000000..bdf43be7
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_selfdestruct.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(address payable a) public {
+ selfdestruct(a);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol
new file mode 100644
index 00000000..40f85ccc
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion.sol
@@ -0,0 +1,11 @@
+contract C {
+ address payable[] a;
+ address[] b;
+ function f() public view {
+ address payable[] storage c = a;
+ address[] storage d = b;
+ d = c; // TODO: this could be allowed in the future
+ }
+}
+// ----
+// TypeError: (172-173): Type address payable[] storage pointer is not implicitly convertible to expected type address[] storage pointer.
diff --git a/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol
new file mode 100644
index 00000000..3c3eb859
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_payable_storage_array_conversion_fail.sol
@@ -0,0 +1,11 @@
+contract C {
+ address payable[] a;
+ address[] b;
+ function f() public view {
+ address payable[] storage c = a;
+ address[] storage d = b;
+ c = d;
+ }
+}
+// ----
+// TypeError: (172-173): Type address[] storage pointer is not implicitly convertible to expected type address payable[] storage pointer.
diff --git a/test/libsolidity/syntaxTests/types/address_to_contract.sol b/test/libsolidity/syntaxTests/types/address/address_to_contract.sol
index 629a3df0..629a3df0 100644
--- a/test/libsolidity/syntaxTests/types/address_to_contract.sol
+++ b/test/libsolidity/syntaxTests/types/address/address_to_contract.sol
diff --git a/test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol b/test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol
new file mode 100644
index 00000000..c9e5ddf6
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_to_contract_implicitly.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f() public view {
+ C c = address(2);
+ }
+}
+// ----
+// TypeError: (46-62): Type address payable is not implicitly convertible to expected type contract C.
diff --git a/test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol b/test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol
new file mode 100644
index 00000000..6917444b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_to_contract_payable_fallback.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f() public pure returns (C c) {
+ c = C(address(2));
+ }
+ function() external payable {
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol
new file mode 100644
index 00000000..1aab9b51
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_to_payable_address.sol
@@ -0,0 +1,10 @@
+contract C {
+ function f(address a) public pure {
+ address b;
+ address payable c = a;
+ c = b;
+ }
+}
+// ----
+// TypeError: (80-101): Type address is not implicitly convertible to expected type address payable.
+// TypeError: (115-116): Type address is not implicitly convertible to expected type address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol b/test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol
new file mode 100644
index 00000000..1e755033
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_to_payable_address_double.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f(address a) public pure returns (address payable) {
+ return address(address(a));
+ }
+}
+// ----
+// TypeError: (94-113): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol b/test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol
new file mode 100644
index 00000000..17e9e7c1
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_tuple_fail.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f() public view returns (address payable a, address b) {
+ (address c, address payable d) = (address(this), address(0));
+ (a,b) = (c,d);
+ }
+}
+// ----
+// TypeError: (169-174): Type tuple(address,address payable) is not implicitly convertible to expected type tuple(address payable,address).
diff --git a/test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol b/test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol
new file mode 100644
index 00000000..846de1f4
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/address_tuple_fine.sol
@@ -0,0 +1,6 @@
+contract C {
+ function f() public view returns (address payable a, address b) {
+ (address c, address payable d) = (address(this), address(0));
+ (a,b) = (d,c);
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol
new file mode 100644
index 00000000..ef87ac55
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/bytes_long_to_payable_address.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f(bytes32 x) public pure returns (address payable) {
+ return address(x);
+ }
+}
+// ----
+// TypeError: (94-104): Explicit type conversion not allowed from "bytes32" to "address".
+// TypeError: (94-104): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol
new file mode 100644
index 00000000..2aa60251
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/bytes_short_to_payable_address.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f(bytes10 x) public pure returns (address payable) {
+ return address(x);
+ }
+}
+// ----
+// TypeError: (94-104): Explicit type conversion not allowed from "bytes10" to "address".
+// TypeError: (94-104): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol
new file mode 100644
index 00000000..5b6a6714
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/bytes_to_payable_address.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(bytes20 x) public pure returns (address payable) {
+ return address(x);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol
new file mode 100644
index 00000000..777bce00
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/contract_no_fallback_to_payable_address.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f() public view {
+ address payable a = address(this);
+ a;
+ }
+}
+// ----
+// TypeError: (46-79): Type address is not implicitly convertible to expected type address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol
new file mode 100644
index 00000000..6518eebb
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/contract_non_payable_fallback_to_payable_address.sol
@@ -0,0 +1,10 @@
+contract C {
+ function f() public view {
+ address payable a = address(this);
+ a;
+ }
+ function() external {
+ }
+}
+// ----
+// TypeError: (46-79): Type address is not implicitly convertible to expected type address payable.
diff --git a/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol
new file mode 100644
index 00000000..359beeb4
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address.sol
@@ -0,0 +1,9 @@
+contract C {
+ function f() public view {
+ address payable a = address(this);
+ a;
+ }
+ function() external payable {
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol
new file mode 100644
index 00000000..4b20b1c6
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/contract_payable_fallback_to_payable_address_implicitly.sol
@@ -0,0 +1,10 @@
+contract C {
+ function f() public view {
+ address payable a = this;
+ a;
+ }
+ function() external payable {
+ }
+}
+// ----
+// TypeError: (46-70): Type contract C is not implicitly convertible to expected type address payable.
diff --git a/test/libsolidity/syntaxTests/types/contract_to_address.sol b/test/libsolidity/syntaxTests/types/address/contract_to_address.sol
index ec2f8184..ec2f8184 100644
--- a/test/libsolidity/syntaxTests/types/contract_to_address.sol
+++ b/test/libsolidity/syntaxTests/types/address/contract_to_address.sol
diff --git a/test/libsolidity/syntaxTests/types/contract_to_address_implicitly.sol b/test/libsolidity/syntaxTests/types/address/contract_to_address_implicitly.sol
index 8be9daac..8be9daac 100644
--- a/test/libsolidity/syntaxTests/types/contract_to_address_implicitly.sol
+++ b/test/libsolidity/syntaxTests/types/address/contract_to_address_implicitly.sol
diff --git a/test/libsolidity/syntaxTests/types/address/literal_to_address.sol b/test/libsolidity/syntaxTests/types/address/literal_to_address.sol
new file mode 100644
index 00000000..20ee56de
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/literal_to_address.sol
@@ -0,0 +1,9 @@
+contract C {
+ function f() public pure {
+ address a = address(0);
+ a = address(1);
+ address b = 0x0123456789012345678901234567890123456789;
+ b = 0x9876543210987654321098765432109876543210;
+ b = 0x9876_5432_1098_7654_3210_9876_5432_1098_7654_3210;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol
new file mode 100644
index 00000000..97f4d85d
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/literal_to_payable_address.sol
@@ -0,0 +1,8 @@
+contract C {
+ function f() public pure {
+ address payable a = address(0);
+ a = address(1);
+ address payable b = 0x0123456789012345678901234567890123456789;
+ b = 0x9876543210987654321098765432109876543210;
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol b/test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol
new file mode 100644
index 00000000..e13a0897
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/nonpayable_address_to_contract_payable_fallback.sol
@@ -0,0 +1,10 @@
+contract C {
+ function f() public pure returns (C c) {
+ address a = address(2);
+ c = C(a);
+ }
+ function() external payable {
+ }
+}
+// ----
+// TypeError: (92-96): Explicit type conversion not allowed from non-payable "address" to "contract C", which has a payable fallback function.
diff --git a/test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol b/test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol
new file mode 100644
index 00000000..f5dbf937
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/payable_address_to_address.sol
@@ -0,0 +1,7 @@
+contract C {
+ function f(address payable a) public pure {
+ address payable b;
+ address c = a;
+ c = b;
+ }
+} \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol b/test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol
new file mode 100644
index 00000000..9a33985a
--- /dev/null
+++ b/test/libsolidity/syntaxTests/types/address/uint_to_payable_address.sol
@@ -0,0 +1,5 @@
+contract C {
+ function f(uint x) public pure returns (address payable) {
+ return address(x);
+ }
+}
diff --git a/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol b/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol
deleted file mode 100644
index efab7c27..00000000
--- a/test/libsolidity/syntaxTests/types/address_to_contract_implicitly.sol
+++ /dev/null
@@ -1,7 +0,0 @@
-contract C {
- function f() public view {
- C c = address(2);
- }
-}
-// ----
-// TypeError: (46-62): Type address is not implicitly convertible to expected type contract C.
diff --git a/test/libsolidity/syntaxTests/unicode_escape_literals.sol b/test/libsolidity/syntaxTests/unicode_escape_literals.sol
new file mode 100644
index 00000000..a340487b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/unicode_escape_literals.sol
@@ -0,0 +1,31 @@
+contract test {
+
+ function oneByteUTF8() public pure returns (bytes32) {
+ bytes32 usdollar = "aaa\u0024aaa";
+ return usdollar;
+ }
+
+ function twoBytesUTF8() public pure returns (bytes32) {
+ bytes32 cent = "aaa\u00A2aaa";
+ return cent;
+ }
+
+ function threeBytesUTF8() public pure returns (bytes32) {
+ bytes32 eur = "aaa\u20ACaaa";
+ return eur;
+ }
+
+ function together() public pure returns (bytes32) {
+ bytes32 res = "\u0024\u00A2\u20AC";
+ return res;
+ }
+
+ // this function returns an invalid unicode character
+ function invalidLiteral() public pure returns(bytes32) {
+ bytes32 invalid = "\u00xx";
+ return invalid;
+ }
+
+}
+// ----
+// ParserError: (678-681): Expected primary expression.
diff --git a/test/libsolidity/syntaxTests/unterminatedBlocks/one_dot.sol b/test/libsolidity/syntaxTests/unterminatedBlocks/one_dot.sol
new file mode 100644
index 00000000..a678f004
--- /dev/null
+++ b/test/libsolidity/syntaxTests/unterminatedBlocks/one_dot.sol
@@ -0,0 +1,4 @@
+contract c {
+ function f() pure public { 1.
+// ----
+// ParserError: (47-47): Expected identifier but got end of source \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/unterminatedBlocks/one_dot_x.sol b/test/libsolidity/syntaxTests/unterminatedBlocks/one_dot_x.sol
new file mode 100644
index 00000000..3cc59374
--- /dev/null
+++ b/test/libsolidity/syntaxTests/unterminatedBlocks/one_dot_x.sol
@@ -0,0 +1,5 @@
+contract test {
+ function f() pure public { 1.x; }
+}
+// ----
+// TypeError: (47-50): Member "x" not found or not visible after argument-dependent lookup in int_const 1. \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot.sol b/test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot.sol
new file mode 100644
index 00000000..6ba2b4c2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot.sol
@@ -0,0 +1,4 @@
+contract c {
+ function f() pure public { 0.
+// ----
+// ParserError: (47-47): Expected identifier but got end of source \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot_x.sol b/test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot_x.sol
new file mode 100644
index 00000000..8648bce2
--- /dev/null
+++ b/test/libsolidity/syntaxTests/unterminatedBlocks/zero_dot_x.sol
@@ -0,0 +1,5 @@
+contract test {
+ function f() pure public { 0.x; }
+}
+// ----
+// TypeError: (47-50): Member "x" not found or not visible after argument-dependent lookup in int_const 0. \ No newline at end of file
diff --git a/test/libsolidity/syntaxTests/upper_case_hex_literals.sol b/test/libsolidity/syntaxTests/upper_case_hex_literals.sol
new file mode 100644
index 00000000..0842c2ec
--- /dev/null
+++ b/test/libsolidity/syntaxTests/upper_case_hex_literals.sol
@@ -0,0 +1,9 @@
+contract test {
+
+ function f() public pure returns (uint256) {
+ uint256 a = 0x1234aAbcC;
+ uint256 b = 0x1234ABCDEF;
+ return a + b;
+ }
+}
+// ----
diff --git a/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol b/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol
index f951feb4..5356f0b8 100644
--- a/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol
+++ b/test/libsolidity/syntaxTests/viewPureChecker/builtin_functions_view_fail.sol
@@ -16,6 +16,8 @@ contract C {
(bool success,) = address(this).call("");
require(success);
}
+ function() payable external {
+ }
}
// ----
// TypeError: (52-77): Function declared as view, but this expression (potentially) modifies the state and thus requires non-payable (the default) or payable.
diff --git a/test/tools/fuzzer.cpp b/test/tools/fuzzer.cpp
index a5a63854..ce4b721f 100644
--- a/test/tools/fuzzer.cpp
+++ b/test/tools/fuzzer.cpp
@@ -84,12 +84,8 @@ void testConstantOptimizer()
}
}
-void testStandardCompiler()
+void runCompiler(string input)
{
- if (!quiet)
- cout << "Testing compiler via JSON interface." << endl;
- string input = readStandardInput();
-
string outputString(compileStandard(input.c_str(), NULL));
Json::Value output;
if (!jsonParseStrict(outputString, output))
@@ -112,52 +108,37 @@ void testStandardCompiler()
}
}
+void testStandardCompiler()
+{
+ if (!quiet)
+ cout << "Testing compiler via JSON interface." << endl;
+ string input = readStandardInput();
+
+ runCompiler(input);
+}
+
void testCompiler(bool optimize)
{
if (!quiet)
cout << "Testing compiler " << (optimize ? "with" : "without") << " optimizer." << endl;
string input = readStandardInput();
- string outputString(compileJSON(input.c_str(), optimize));
- Json::Value outputJson;
- if (!jsonParseStrict(outputString, outputJson))
- {
- cout << "Compiler produced invalid JSON output." << endl;
- abort();
- }
- if (outputJson.isMember("errors"))
- {
- if (!outputJson["errors"].isArray())
- {
- cout << "Output JSON has \"errors\" but it is not an array." << endl;
- abort();
- }
- for (Json::Value const& error: outputJson["errors"])
- {
- string invalid = contains(error.asString(), vector<string>{
- // StandardJSON error types
- "Exception",
- "InternalCompilerError",
- // Old-school error messages
- "Internal compiler error",
- "Exception during compilation",
- "Unknown exception during compilation",
- "Unknown exception while generating contract data output",
- "Unknown exception while generating source name output",
- "Unknown error while generating JSON"
- });
- if (!invalid.empty())
- {
- cout << "Invalid error: \"" << error.asString() << "\"" << endl;
- abort();
- }
- }
- }
- else if (!outputJson.isMember("contracts"))
- {
- cout << "Output JSON has neither \"errors\" nor \"contracts\"." << endl;
- abort();
- }
+ Json::Value config = Json::objectValue;
+ config["language"] = "Solidity";
+ config["sources"] = Json::objectValue;
+ config["sources"][""] = Json::objectValue;
+ config["sources"][""]["content"] = input;
+ config["settings"] = Json::objectValue;
+ config["settings"]["optimizer"] = Json::objectValue;
+ config["settings"]["optimizer"]["enabled"] = optimize;
+ config["settings"]["optimizer"]["runs"] = 200;
+
+ // Enable all SourceUnit-level outputs.
+ config["settings"]["outputSelection"]["*"][""][0] = "*";
+ // Enable all Contract-level outputs.
+ config["settings"]["outputSelection"]["*"]["*"][0] = "*";
+
+ runCompiler(jsonCompactPrint(config));
}
}