aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--CMakeLists.txt2
-rw-r--r--Changelog.md27
-rw-r--r--appveyor.yml18
-rw-r--r--docs/abi-spec.rst2
-rw-r--r--docs/bugs.json7
-rw-r--r--docs/bugs.rst2
-rw-r--r--docs/bugs_by_version.json49
-rw-r--r--docs/grammar.txt2
-rw-r--r--docs/index.rst3
-rw-r--r--docs/installing-solidity.rst2
-rw-r--r--docs/miscellaneous.rst2
-rw-r--r--docs/solidity-by-example.rst12
-rw-r--r--docs/types.rst6
-rw-r--r--libdevcore/CommonIO.cpp20
-rw-r--r--libdevcore/CommonIO.h5
-rw-r--r--libevmasm/Assembly.cpp3
-rw-r--r--libevmasm/PeepholeOptimiser.cpp11
-rw-r--r--libevmasm/SemanticInformation.cpp2
-rw-r--r--liblll/CodeFragment.cpp44
-rw-r--r--libsolidity/CMakeLists.txt4
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp33
-rw-r--r--libsolidity/analysis/ConstantEvaluator.h8
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp6
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp20
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp16
-rw-r--r--libsolidity/analysis/TypeChecker.cpp18
-rw-r--r--libsolidity/ast/AST.cpp6
-rw-r--r--libsolidity/ast/AST.h5
-rw-r--r--libsolidity/ast/ASTForward.h1
-rw-r--r--libsolidity/ast/Types.cpp9
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp37
-rw-r--r--libsolidity/codegen/ABIFunctions.h6
-rw-r--r--libsolidity/codegen/ArrayUtils.cpp3
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp11
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp14
-rw-r--r--libsolidity/formal/SMTChecker.cpp28
-rw-r--r--libsolidity/formal/SMTChecker.h4
-rw-r--r--libsolidity/formal/SMTLib2Interface.cpp9
-rw-r--r--libsolidity/formal/SMTLib2Interface.h8
-rw-r--r--libsolidity/formal/Z3Interface.cpp48
-rw-r--r--libsolidity/interface/CompilerStack.cpp48
-rw-r--r--libsolidity/interface/CompilerStack.h42
-rw-r--r--libsolidity/interface/SourceReferenceFormatter.cpp15
-rw-r--r--libsolidity/interface/StandardCompiler.cpp19
-rw-r--r--lllc/main.cpp36
-rwxr-xr-xscripts/install_deps.sh1
-rwxr-xr-xscripts/test_emscripten.sh4
-rwxr-xr-xscripts/tests.sh5
-rw-r--r--solc/CommandLineInterface.cpp41
-rw-r--r--test/ExecutionFramework.h67
-rw-r--r--test/RPCSession.cpp28
-rw-r--r--test/RPCSession.h1
-rw-r--r--test/contracts/AuctionRegistrar.cpp2
-rw-r--r--test/contracts/ContractInterface.h99
-rw-r--r--test/contracts/Wallet.cpp40
-rw-r--r--test/libevmasm/Optimiser.cpp14
-rw-r--r--test/liblll/Compiler.cpp532
-rw-r--r--test/libsolidity/ABIEncoderTests.cpp81
-rw-r--r--test/libsolidity/AnalysisFramework.cpp2
-rw-r--r--test/libsolidity/Assembly.cpp2
-rw-r--r--test/libsolidity/GasMeter.cpp14
-rw-r--r--test/libsolidity/SMTChecker.cpp26
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp344
-rw-r--r--test/libsolidity/SolidityExecutionFramework.h2
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp230
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp4
-rw-r--r--test/libsolidity/StandardCompiler.cpp177
-rw-r--r--test/libsolidity/ViewPureChecker.cpp7
70 files changed, 2062 insertions, 338 deletions
diff --git a/.travis.yml b/.travis.yml
index 708d3620..a2301c42 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -184,8 +184,10 @@ before_script:
script:
- test $SOLC_EMSCRIPTEN != On || (scripts/test_emscripten.sh)
+ - test $? == 0 || SOLC_STOREBYTECODE=Off
- test $SOLC_DOCS != On || (scripts/docs.sh)
- test $SOLC_TESTS != On || (cd $TRAVIS_BUILD_DIR && scripts/tests.sh)
+ - test $? == 0 || SOLC_STOREBYTECODE=Off
- test $SOLC_STOREBYTECODE != On || (cd $TRAVIS_BUILD_DIR && scripts/bytecodecompare/storebytecode.sh)
deploy:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 537a9521..24bea3b3 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.18")
+set(PROJECT_VERSION "0.4.19")
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 8ebc30d0..45521f3e 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,16 +1,39 @@
-### 0.4.18 (unreleased)
+### 0.4.19 (unreleased)
Features:
+ * Syntax Checker: Turn the usage of ``callcode`` into an error as experimental 0.5.0 feature.
+ * Type Checker: More detailed errors for invalid array lengths (such as division by zero).
+
+Bugfixes:
+
+### 0.4.18 (2017-10-18)
+
+Features:
+ * Code Generator: Always use all available gas for calls as experimental 0.5.0 feature
+ (previously, some amount was retained in order to work in pre-Tangerine-Whistle
+ EVM versions)
* Parser: Better error message for unexpected trailing comma in parameter lists.
+ * Standard JSON: Support the ``outputSelection`` field for selective compilation of supplied sources.
* Syntax Checker: Unary ``+`` is now a syntax error as experimental 0.5.0 feature.
* Type Checker: Disallow non-pure constant state variables as experimental 0.5.0 feature.
+ * Type Checker: Do not add members of ``address`` to contracts as experimental 0.5.0 feature.
+ * Type Checker: Force interface functions to be external as experimental 0.5.0 feature.
+ * Type Checker: Require ``storage`` or ``memory`` keyword for local variables as experimental 0.5.0 feature.
+ * Compiler Interface: Better formatted error message for long source snippets
Bugfixes:
+ * Code Generator: Allocate one byte per memory byte array element instead of 32.
+ * Code Generator: Do not accept data with less than four bytes (truncated function
+ signature) for regular function calls - fallback function is invoked instead.
+ * Optimizer: Remove unused stack computation results.
* Parser: Fix source location of VariableDeclarationStatement.
+ * Type Checker: Allow ``gas`` in view functions.
+ * Type Checker: Do not mark event parameters as shadowing state variables.
+ * Type Checker: Prevent duplicate event declarations.
* Type Checker: Properly check array length and don't rely on an assertion in code generation.
* Type Checker: Properly support overwriting members inherited from ``address`` in a contract
(such as ``balance``, ``transfer``, etc.)
- * Type Checker: Prevent duplicate event declarations.
+ * Type Checker: Validate each number literal in tuple expressions even if they are not assigned from.
### 0.4.17 (2017-09-21)
diff --git a/appveyor.yml b/appveyor.yml
index b50681b9..ef5f6907 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -47,10 +47,12 @@ environment:
#init:
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
install:
- - ps: $fileContent = "-----BEGIN RSA PRIVATE KEY-----`n"
- - ps: $fileContent += $env:priv_key.Replace(' ', "`n")
- - ps: $fileContent += "`n-----END RSA PRIVATE KEY-----`n"
- - ps: Set-Content c:\users\appveyor\.ssh\id_rsa $fileContent
+ - ps: if ($env:priv_key) {
+ $fileContent = "-----BEGIN RSA PRIVATE KEY-----`n";
+ $fileContent += $env:priv_key.Replace(' ', "`n");
+ $fileContent += "`n-----END RSA PRIVATE KEY-----`n";
+ Set-Content c:\users\appveyor\.ssh\id_rsa $fileContent
+ }
- git submodule update --init --recursive
- ps: $prerelease = "nightly."
- ps: $prerelease += Get-Date -format "yyyy.M.d"
@@ -66,12 +68,16 @@ build_script:
- cd %APPVEYOR_BUILD_FOLDER%
- scripts\release.bat %CONFIGURATION%
- ps: $bytecodedir = git show -s --format="%cd-%H" --date=short
- - ps: scripts\bytecodecompare\storebytecode.bat $Env:CONFIGURATION $bytecodedir
test_script:
- - cd %APPVEYOR_BUILD_FOLDER%
- cd %APPVEYOR_BUILD_FOLDER%\build\test\%CONFIGURATION%
- soltest.exe --show-progress -- --no-ipc --no-smt
+# Skip bytecode compare if private key is not available
+ - cd %APPVEYOR_BUILD_FOLDER%
+ - ps: if ($env:priv_key) {
+ scripts\bytecodecompare\storebytecode.bat $Env:CONFIGURATION $bytecodedir
+ }
+ - cd %APPVEYOR_BUILD_FOLDER%\build\test\%CONFIGURATION%
artifacts:
- path: solidity-windows.zip
diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst
index 0361458f..43757d24 100644
--- a/docs/abi-spec.rst
+++ b/docs/abi-spec.rst
@@ -279,7 +279,7 @@ Events
Events are an abstraction of the Ethereum logging/event-watching protocol. Log entries provide the contract's address, a series of up to four topics and some arbitrary length binary data. Events leverage the existing function ABI in order to interpret this (together with an interface spec) as a properly typed structure.
-Given an event name and series of event parameters, we split them into two sub-series: those which are indexed and those which are not. Those which are indexed, which may number up to 3, are used alongside the Keccak hash of the event signature to form the topics of the log entry. Those which as not indexed form the byte array of the event.
+Given an event name and series of event parameters, we split them into two sub-series: those which are indexed and those which are not. Those which are indexed, which may number up to 3, are used alongside the Keccak hash of the event signature to form the topics of the log entry. Those which are not indexed form the byte array of the event.
In effect, a log entry using this ABI is described as:
diff --git a/docs/bugs.json b/docs/bugs.json
index ac322a48..c642793a 100644
--- a/docs/bugs.json
+++ b/docs/bugs.json
@@ -1,5 +1,12 @@
[
{
+ "name": "ZeroFunctionSelector",
+ "summary": "It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.",
+ "description": "If a function has a selector consisting only of zeros, is payable and part of a contract that does not have a fallback function and at most five external functions in total, this function is called instead of the fallback function if Ether is sent to the contract without data.",
+ "fixed": "0.4.18",
+ "severity": "very low"
+ },
+ {
"name": "DelegateCallReturnValue",
"summary": "The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.",
"description": "The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides. This value is interpreted as a boolean and put onto the stack. This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successuful.",
diff --git a/docs/bugs.rst b/docs/bugs.rst
index 55771a35..7629830d 100644
--- a/docs/bugs.rst
+++ b/docs/bugs.rst
@@ -48,7 +48,7 @@ fixed
publish
The date at which the bug became known publicly, optional
severity
- Severity of the bug: low, medium, high. Takes into account
+ Severity of the bug: very low, low, medium, high. Takes into account
discoverability in contract tests, likelihood of occurrence and
potential damage by exploits.
conditions
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index c3686ebf..cca45428 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -1,6 +1,7 @@
{
"0.1.0": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -17,6 +18,7 @@
},
"0.1.1": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -33,6 +35,7 @@
},
"0.1.2": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -49,6 +52,7 @@
},
"0.1.3": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -65,6 +69,7 @@
},
"0.1.4": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -81,6 +86,7 @@
},
"0.1.5": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -97,6 +103,7 @@
},
"0.1.6": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -114,6 +121,7 @@
},
"0.1.7": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -131,6 +139,7 @@
},
"0.2.0": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -148,6 +157,7 @@
},
"0.2.1": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -165,6 +175,7 @@
},
"0.2.2": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -182,6 +193,7 @@
},
"0.3.0": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -199,6 +211,7 @@
},
"0.3.1": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -215,6 +228,7 @@
},
"0.3.2": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -231,6 +245,7 @@
},
"0.3.3": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -246,6 +261,7 @@
},
"0.3.4": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -261,6 +277,7 @@
},
"0.3.5": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -276,6 +293,7 @@
},
"0.3.6": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -289,6 +307,7 @@
},
"0.4.0": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -302,6 +321,7 @@
},
"0.4.1": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -315,6 +335,7 @@
},
"0.4.10": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -324,6 +345,7 @@
},
"0.4.11": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral"
@@ -332,6 +354,7 @@
},
"0.4.12": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
],
@@ -339,6 +362,7 @@
},
"0.4.13": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
],
@@ -346,24 +370,36 @@
},
"0.4.14": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue"
],
"released": "2017-07-31"
},
"0.4.15": {
- "bugs": [],
+ "bugs": [
+ "ZeroFunctionSelector"
+ ],
"released": "2017-08-08"
},
"0.4.16": {
- "bugs": [],
+ "bugs": [
+ "ZeroFunctionSelector"
+ ],
"released": "2017-08-24"
},
"0.4.17": {
- "bugs": [],
+ "bugs": [
+ "ZeroFunctionSelector"
+ ],
"released": "2017-09-21"
},
+ "0.4.18": {
+ "bugs": [],
+ "released": "2017-10-18"
+ },
"0.4.2": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -376,6 +412,7 @@
},
"0.4.3": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -387,6 +424,7 @@
},
"0.4.4": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -397,6 +435,7 @@
},
"0.4.5": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -408,6 +447,7 @@
},
"0.4.6": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -418,6 +458,7 @@
},
"0.4.7": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -427,6 +468,7 @@
},
"0.4.8": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -436,6 +478,7 @@
},
"0.4.9": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
diff --git a/docs/grammar.txt b/docs/grammar.txt
index 041728c5..72364b7c 100644
--- a/docs/grammar.txt
+++ b/docs/grammar.txt
@@ -145,7 +145,7 @@ Byte = 'byte' | 'bytes' | 'bytes1' | 'bytes2' | 'bytes3' | 'bytes4' | 'bytes5' |
Fixed = 'fixed' | ( 'fixed' DecimalNumber 'x' DecimalNumber )
-Uixed = 'ufixed' | ( 'ufixed' DecimalNumber 'x' DecimalNumber )
+Ufixed = 'ufixed' | ( 'ufixed' DecimalNumber 'x' DecimalNumber )
InlineAssemblyBlock = '{' AssemblyItem* '}'
diff --git a/docs/index.rst b/docs/index.rst
index cb093bd6..351f8ad7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -61,6 +61,9 @@ Available Solidity Integrations
* `Solium <https://github.com/duaraghav8/Solium/>`_
A commandline linter for Solidity which strictly follows the rules prescribed by the `Solidity Style Guide <http://solidity.readthedocs.io/en/latest/style-guide.html>`_.
+
+* `Solhint <https://github.com/protofire/solhint>`_
+ Solidity linter that provides security, style guide and best practice rules for smart contract validation.
* `Visual Studio Code extension <http://juan.blanco.ws/solidity-contracts-in-visual-studio-code/>`_
Solidity plugin for Microsoft Visual Studio Code that includes syntax highlighting and the Solidity compiler.
diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst
index 71607745..b660cf02 100644
--- a/docs/installing-solidity.rst
+++ b/docs/installing-solidity.rst
@@ -230,6 +230,8 @@ Or, on Windows:
Command-Line Build
------------------
+**Be sure to install External Dependencies (see above) before build.**
+
Solidity project uses CMake to configure the build.
Building Solidity is quite similar on Linux, macOS and other Unices:
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index 6c0efa9e..1c4f918c 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -332,7 +332,7 @@ Global Variables
- ``this`` (current contract's type): the current contract, explicitly convertible to ``address``
- ``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 recipieint)``: an alias to ``selfdestruct``
+- ``suicide(address recipient)``: an alias to ``selfdestruct``
- ``<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
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index 139c8a42..59ab7962 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -221,8 +221,7 @@ activate themselves.
// absolute unix timestamps (seconds since 1970-01-01)
// or time periods in seconds.
address public beneficiary;
- uint public auctionStart;
- uint public biddingTime;
+ uint public auctionEnd;
// Current state of the auction.
address public highestBidder;
@@ -251,8 +250,7 @@ activate themselves.
address _beneficiary
) {
beneficiary = _beneficiary;
- auctionStart = now;
- biddingTime = _biddingTime;
+ auctionEnd = now + _biddingTime;
}
/// Bid on the auction with the value sent
@@ -268,7 +266,7 @@ activate themselves.
// Revert the call if the bidding
// period is over.
- require(now <= (auctionStart + biddingTime));
+ require(now <= auctionEnd);
// If the bid is not higher, send the
// money back.
@@ -322,7 +320,7 @@ activate themselves.
// external contracts.
// 1. Conditions
- require(now >= (auctionStart + biddingTime)); // auction did not yet end
+ require(now >= auctionEnd); // auction did not yet end
require(!ended); // this function has already been called
// 2. Effects
@@ -382,7 +380,6 @@ high or low invalid bids.
}
address public beneficiary;
- uint public auctionStart;
uint public biddingEnd;
uint public revealEnd;
bool public ended;
@@ -410,7 +407,6 @@ high or low invalid bids.
address _beneficiary
) {
beneficiary = _beneficiary;
- auctionStart = now;
biddingEnd = now + _biddingTime;
revealEnd = biddingEnd + _revealTime;
}
diff --git a/docs/types.rst b/docs/types.rst
index 5c291f35..774c1d04 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -107,6 +107,9 @@ Operators:
* ``<=``, ``<``, ``==``, ``!=``, ``>=`` and ``>``
+.. note::
+ Starting with version 0.5.0 contracts do not derive from the address type, but can still be explicitly converted to address.
+
.. _members-of-addresses:
Members of Addresses
@@ -240,6 +243,9 @@ 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.
+.. note::
+ The mixed-case address checksum format is defined in `EIP-55 <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md>`_.
+
.. index:: literal, literal;rational
.. _rational_literals:
diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp
index 5d47937b..8c7e08f6 100644
--- a/libdevcore/CommonIO.cpp
+++ b/libdevcore/CommonIO.cpp
@@ -39,7 +39,7 @@ namespace
{
template <typename _T>
-inline _T contentsGeneric(std::string const& _file)
+inline _T readFile(std::string const& _file)
{
_T ret;
size_t const c_elementSize = sizeof(typename _T::value_type);
@@ -61,9 +61,23 @@ inline _T contentsGeneric(std::string const& _file)
}
-string dev::contentsString(string const& _file)
+string dev::readFileAsString(string const& _file)
{
- return contentsGeneric<string>(_file);
+ return readFile<string>(_file);
+}
+
+string dev::readStandardInput()
+{
+ string ret;
+ while (!cin.eof())
+ {
+ string tmp;
+ // NOTE: this will read until EOF or NL
+ getline(cin, tmp);
+ ret.append(tmp);
+ ret.append("\n");
+ }
+ return ret;
}
void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename)
diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h
index d84362cf..33769ec3 100644
--- a/libdevcore/CommonIO.h
+++ b/libdevcore/CommonIO.h
@@ -32,7 +32,10 @@ namespace dev
/// Retrieve and returns the contents of the given file as a std::string.
/// If the file doesn't exist or isn't readable, returns an empty container / bytes.
-std::string contentsString(std::string const& _file);
+std::string readFileAsString(std::string const& _file);
+
+/// Retrieve and returns the contents of standard input (until EOF).
+std::string readStandardInput();
/// Write the given binary data into the given file, replacing the file if it pre-exists.
/// Throws exception on error.
diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp
index df691e7d..5fab24e1 100644
--- a/libevmasm/Assembly.cpp
+++ b/libevmasm/Assembly.cpp
@@ -408,7 +408,10 @@ map<u256, u256> Assembly::optimiseInternal(
{
PeepholeOptimiser peepOpt(m_items);
while (peepOpt.optimise())
+ {
count++;
+ assertThrow(count < 64000, OptimizerException, "Peephole optimizer seems to be stuck.");
+ }
}
// This only modifies PushTags, we have to run again to actually remove code.
diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp
index 31fdd317..168d1109 100644
--- a/libevmasm/PeepholeOptimiser.cpp
+++ b/libevmasm/PeepholeOptimiser.cpp
@@ -249,6 +249,11 @@ void applyMethods(OptimiserState& _state, Method, OtherMethods... _other)
applyMethods(_state, _other...);
}
+size_t numberOfPops(AssemblyItems const& _items)
+{
+ return std::count(_items.begin(), _items.end(), Instruction::POP);
+}
+
}
bool PeepholeOptimiser::optimise()
@@ -257,8 +262,10 @@ bool PeepholeOptimiser::optimise()
while (state.i < m_items.size())
applyMethods(state, PushPop(), OpPop(), DoublePush(), DoubleSwap(), JumpToNext(), UnreachableCode(), TagConjunctions(), Identity());
if (m_optimisedItems.size() < m_items.size() || (
- m_optimisedItems.size() == m_items.size() &&
- eth::bytesRequired(m_optimisedItems, 3) < eth::bytesRequired(m_items, 3)
+ m_optimisedItems.size() == m_items.size() && (
+ eth::bytesRequired(m_optimisedItems, 3) < eth::bytesRequired(m_items, 3) ||
+ numberOfPops(m_optimisedItems) > numberOfPops(m_items)
+ )
))
{
m_items = std::move(m_optimisedItems);
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp
index 83cfe2c6..61a6ccda 100644
--- a/libevmasm/SemanticInformation.cpp
+++ b/libevmasm/SemanticInformation.cpp
@@ -198,6 +198,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
case Instruction::ORIGIN:
case Instruction::CALLER:
case Instruction::CALLVALUE:
+ case Instruction::GAS:
case Instruction::GASPRICE:
case Instruction::EXTCODESIZE:
case Instruction::EXTCODECOPY:
@@ -223,7 +224,6 @@ bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
case Instruction::SSTORE:
case Instruction::JUMP:
case Instruction::JUMPI:
- case Instruction::GAS:
case Instruction::LOG0:
case Instruction::LOG1:
case Instruction::LOG2:
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index d4ef3888..5c68194b 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -47,6 +47,32 @@ void CodeFragment::finalise(CompilerState const& _cs)
}
}
+namespace
+{
+/// Returns true iff the instruction is valid in "inline assembly".
+bool validAssemblyInstruction(string us)
+{
+ auto it = c_instructions.find(us);
+ return !(
+ it == c_instructions.end() ||
+ solidity::isPushInstruction(it->second)
+ );
+}
+
+/// Returns true iff the instruction is valid as a function.
+bool validFunctionalInstruction(string us)
+{
+ auto it = c_instructions.find(us);
+ return !(
+ it == c_instructions.end() ||
+ solidity::isPushInstruction(it->second) ||
+ solidity::isDupInstruction(it->second) ||
+ solidity::isSwapInstruction(it->second) ||
+ it->second == solidity::Instruction::JUMPDEST
+ );
+}
+}
+
CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback const& _readFile, bool _allowASM):
m_readFile(_readFile)
{
@@ -80,7 +106,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback
auto sr = _t.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
string s(sr.begin(), sr.end());
string us = boost::algorithm::to_upper_copy(s);
- if (_allowASM && c_instructions.count(us))
+ if (_allowASM && c_instructions.count(us) && validAssemblyInstruction(us))
m_asm.append(c_instructions.at(us));
else if (_s.defs.count(s))
m_asm.append(_s.defs.at(s).m_asm);
@@ -114,22 +140,6 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback
}
}
-namespace
-{
-/// Returns true iff the instruction is valid as a function.
-bool validFunctionalInstruction(string us)
-{
- auto it = c_instructions.find(us);
- return !(
- it == c_instructions.end() ||
- solidity::isPushInstruction(it->second) ||
- solidity::isDupInstruction(it->second) ||
- solidity::isSwapInstruction(it->second) ||
- it->second == solidity::Instruction::JUMPDEST
- );
-}
-}
-
void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
if (_t.tag() == 0 && _t.empty())
diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt
index f7c1a390..99612c40 100644
--- a/libsolidity/CMakeLists.txt
+++ b/libsolidity/CMakeLists.txt
@@ -6,9 +6,9 @@ find_package(Z3 QUIET)
if (${Z3_FOUND})
include_directories(${Z3_INCLUDE_DIR})
add_definitions(-DHAVE_Z3)
- message("Z3 SMT solver FOUND.")
+ message("Z3 SMT solver found. This enables optional SMT checking.")
else()
- message("Z3 SMT solver NOT found.")
+ message("Z3 SMT solver NOT found. Optional SMT checking will not be available. Please install Z3 if it is desired.")
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
endif()
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index 7057eab7..bc3b7cf1 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -22,38 +22,55 @@
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
+#include <libsolidity/interface/ErrorReporter.h>
using namespace std;
using namespace dev;
using namespace dev::solidity;
-
+/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
{
TypePointer const& subType = _operation.subExpression().annotation().type;
if (!dynamic_cast<RationalNumberType const*>(subType.get()))
- BOOST_THROW_EXCEPTION(_operation.subExpression().createTypeError("Invalid constant expression."));
+ m_errorReporter.fatalTypeError(_operation.subExpression().location(), "Invalid constant expression.");
TypePointer t = subType->unaryOperatorResult(_operation.getOperator());
_operation.annotation().type = t;
}
+/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
{
TypePointer const& leftType = _operation.leftExpression().annotation().type;
TypePointer const& rightType = _operation.rightExpression().annotation().type;
if (!dynamic_cast<RationalNumberType const*>(leftType.get()))
- BOOST_THROW_EXCEPTION(_operation.leftExpression().createTypeError("Invalid constant expression."));
+ m_errorReporter.fatalTypeError(_operation.leftExpression().location(), "Invalid constant expression.");
if (!dynamic_cast<RationalNumberType const*>(rightType.get()))
- BOOST_THROW_EXCEPTION(_operation.rightExpression().createTypeError("Invalid constant expression."));
+ m_errorReporter.fatalTypeError(_operation.rightExpression().location(), "Invalid constant expression.");
TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
- if (Token::isCompareOp(_operation.getOperator()))
- commonType = make_shared<BoolType>();
- _operation.annotation().type = commonType;
+ if (!commonType)
+ {
+ m_errorReporter.typeError(
+ _operation.location(),
+ "Operator " +
+ string(Token::toString(_operation.getOperator())) +
+ " not compatible with types " +
+ leftType->toString() +
+ " and " +
+ rightType->toString()
+ );
+ commonType = leftType;
+ }
+ _operation.annotation().commonType = commonType;
+ _operation.annotation().type =
+ Token::isCompareOp(_operation.getOperator()) ?
+ make_shared<BoolType>() :
+ commonType;
}
void ConstantEvaluator::endVisit(Literal const& _literal)
{
_literal.annotation().type = Type::forLiteral(_literal);
if (!_literal.annotation().type)
- BOOST_THROW_EXCEPTION(_literal.createTypeError("Invalid literal value."));
+ m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
}
diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h
index 9ec04ebe..90bceb5d 100644
--- a/libsolidity/analysis/ConstantEvaluator.h
+++ b/libsolidity/analysis/ConstantEvaluator.h
@@ -29,6 +29,7 @@ namespace dev
namespace solidity
{
+class ErrorReporter;
class TypeChecker;
/**
@@ -37,13 +38,18 @@ class TypeChecker;
class ConstantEvaluator: private ASTConstVisitor
{
public:
- ConstantEvaluator(Expression const& _expr) { _expr.accept(*this); }
+ ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter):
+ m_errorReporter(_errorReporter)
+ {
+ _expr.accept(*this);
+ }
private:
virtual void endVisit(BinaryOperation const& _operation);
virtual void endVisit(UnaryOperation const& _operation);
virtual void endVisit(Literal const& _literal);
+ ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index 523e7176..5d010693 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -647,10 +647,12 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
bool warnAboutShadowing = true;
// Do not warn about shadowing for structs and enums because their members are
- // not accessible without prefixes.
+ // not accessible without prefixes. Also do not warn about event parameters
+ // because they don't participate in any proper scope.
if (
dynamic_cast<StructDefinition const*>(m_currentScope) ||
- dynamic_cast<EnumDefinition const*>(m_currentScope)
+ dynamic_cast<EnumDefinition const*>(m_currentScope) ||
+ dynamic_cast<EventDefinition const*>(m_currentScope)
)
warnAboutShadowing = false;
// Do not warn about the constructor shadowing the contract.
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 20016112..f22c95cc 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -147,7 +147,7 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
if (Expression const* length = _typeName.length())
{
if (!length->annotation().type)
- ConstantEvaluator e(*length);
+ ConstantEvaluator e(*length, m_errorReporter);
auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get());
if (!lengthType || !lengthType->mobileType())
fatalTypeError(length->location(), "Invalid array length, expected integer literal.");
@@ -298,11 +298,19 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
{
typeLoc = DataLocation::Storage;
if (_variable.isLocalVariable())
- m_errorReporter.warning(
- _variable.location(),
- "Variable is declared as a storage pointer. "
- "Use an explicit \"storage\" keyword to silence this warning."
- );
+ {
+ if (_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ typeError(
+ _variable.location(),
+ "Storage location must be specified as either \"memory\" or \"storage\"."
+ );
+ else
+ m_errorReporter.warning(
+ _variable.location(),
+ "Variable is declared as a storage pointer. "
+ "Use an explicit \"storage\" keyword to silence this warning."
+ );
+ }
}
}
else
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index ffa538b6..bd8ee597 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -150,10 +150,18 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
if (_memberAccess.memberName() == "callcode")
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
if (type->kind() == FunctionType::Kind::BareCallCode)
- m_errorReporter.warning(
- _memberAccess.location(),
- "\"callcode\" has been deprecated in favour of \"delegatecall\"."
- );
+ {
+ if (m_currentContract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ m_errorReporter.typeError(
+ _memberAccess.location(),
+ "\"callcode\" has been deprecated in favour of \"delegatecall\"."
+ );
+ else
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "\"callcode\" has been deprecated in favour of \"delegatecall\"."
+ );
+ }
if (m_constructor && m_currentContract)
if (ContractType const* type = dynamic_cast<ContractType const*>(_memberAccess.expression().annotation().type.get()))
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index b2a88059..746e762e 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -595,8 +595,16 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
{
if (_function.isImplemented())
m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot have an implementation.");
- if (_function.visibility() < FunctionDefinition::Visibility::Public)
- m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot be internal or private.");
+ if (_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ {
+ if (_function.visibility() != FunctionDefinition::Visibility::External)
+ m_errorReporter.typeError(_function.location(), "Functions in interfaces must be declared external.");
+ }
+ else
+ {
+ if (_function.visibility() < FunctionDefinition::Visibility::Public)
+ m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot be internal or private.");
+ }
if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces.");
}
@@ -1285,6 +1293,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
components[i]->accept(*this);
types.push_back(type(*components[i]));
+
+ // Note: code generation will visit each of the expression even if they are not assigned from.
+ if (types[i]->category() == Type::Category::RationalNumber && components.size() > 1)
+ if (!dynamic_cast<RationalNumberType const&>(*types[i]).mobileType())
+ m_errorReporter.fatalTypeError(components[i]->location(), "Invalid rational number.");
+
if (_tuple.isInlineArray())
solAssert(!!types[i], "Inline array cannot have empty components");
if (_tuple.isInlineArray())
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index a805322b..1048b610 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -22,7 +22,6 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/AST_accept.h>
#include <libdevcore/SHA3.h>
@@ -73,11 +72,6 @@ ASTAnnotation& ASTNode::annotation() const
return *m_annotation;
}
-Error ASTNode::createTypeError(string const& _description) const
-{
- return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
-}
-
SourceUnitAnnotation& SourceUnit::annotation() const
{
if (!m_annotation)
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 75b8e946..733e7c78 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -26,7 +26,6 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/parsing/Token.h>
#include <libsolidity/ast/Types.h>
-#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTEnums.h>
@@ -89,10 +88,6 @@ public:
/// Returns the source code location of this node.
SourceLocation const& location() const { return m_location; }
- /// Creates a @ref TypeError exception and decorates it with the location of the node and
- /// the given description
- Error createTypeError(std::string const& _description) const;
-
///@todo make this const-safe by providing a different way to access the annotation
virtual ASTAnnotation& annotation() const;
diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h
index 15735368..46675e51 100644
--- a/libsolidity/ast/ASTForward.h
+++ b/libsolidity/ast/ASTForward.h
@@ -57,6 +57,7 @@ class UserDefinedTypeName;
class FunctionTypeName;
class Mapping;
class ArrayTypeName;
+class InlineAssembly;
class Statement;
class Block;
class PlaceholderStatement;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index a3cbe50a..ee5f462b 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -1616,9 +1616,10 @@ string ContractType::canonicalName() const
return m_contract.annotation().canonicalName;
}
-MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) const
+MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _contract) const
{
MemberList::MemberMap members;
+ solAssert(_contract, "");
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
@@ -1660,7 +1661,9 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) con
&it.second->declaration()
));
}
- addNonConflictingAddressMembers(members);
+ // In 0.5.0 address members are not populated into the contract.
+ if (!_contract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ addNonConflictingAddressMembers(members);
return members;
}
@@ -2022,7 +2025,7 @@ unsigned EnumType::memberValue(ASTString const& _member) const
return index;
++index;
}
- BOOST_THROW_EXCEPTION(m_enum.createTypeError("Requested unknown enum value ." + _member));
+ solAssert(false, "Requested unknown enum value " + _member);
}
bool TupleType::isImplicitlyConvertibleTo(Type const& _other) const
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index 756148e7..080be359 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -87,7 +87,7 @@ string ABIFunctions::tupleEncoder(
);
elementTempl("values", valueNames);
elementTempl("pos", to_string(headPos));
- elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], _encodeAsLibraryTypes, false));
+ elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], _encodeAsLibraryTypes, true));
encodeElements += elementTempl.render();
headPos += dynamic ? 0x20 : _targetTypes[i]->calldataEncodedSize();
}
@@ -371,7 +371,7 @@ string ABIFunctions::abiEncodingFunction(
Type const& _from,
Type const& _to,
bool _encodeAsLibraryTypes,
- bool _compacted
+ bool _fromStack
)
{
solUnimplementedAssert(
@@ -415,7 +415,7 @@ string ABIFunctions::abiEncodingFunction(
dynamic_cast<FunctionType const&>(_from),
to,
_encodeAsLibraryTypes,
- _compacted
+ _fromStack
);
solAssert(_from.sizeOnStack() == 1, "");
@@ -542,7 +542,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
mstore(pos, sub(tail, headStart))
tail := <encodeToMemoryFun>(<arrayElementAccess>, tail)
srcPtr := <nextArrayElement>(srcPtr)
- pos := add(pos, <elementEncodedSize>)
+ pos := add(pos, 0x20)
}
pos := tail
<assignEnd>
@@ -580,7 +580,7 @@ string ABIFunctions::abiEncodingFunctionSimpleArray(
*_from.baseType(),
*_to.baseType(),
_encodeAsLibraryTypes,
- true
+ false
));
templ("arrayElementAccess", inMemory ? "mload(srcPtr)" : _from.baseType()->isValueType() ? "sload(srcPtr)" : "srcPtr" );
templ("nextArrayElement", nextArrayElementFunction(_from));
@@ -729,7 +729,7 @@ string ABIFunctions::abiEncodingFunctionCompactStorageArray(
*_from.baseType(),
*_to.baseType(),
_encodeAsLibraryTypes,
- true
+ false
);
templ("encodeToMemoryFun", encodeToMemoryFun);
std::vector<std::map<std::string, std::string>> items(itemsPerSlot);
@@ -925,7 +925,7 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
FunctionType const& _from,
Type const& _to,
bool _encodeAsLibraryTypes,
- bool _compacted
+ bool _fromStack
)
{
solAssert(_from.kind() == FunctionType::Kind::External, "");
@@ -936,35 +936,31 @@ string ABIFunctions::abiEncodingFunctionFunctionType(
_from.identifier() +
"_to_" +
_to.identifier() +
- (_compacted ? "_compacted" : "") +
+ (_fromStack ? "_fromStack" : "") +
(_encodeAsLibraryTypes ? "_library" : "");
- if (_compacted)
- {
+ if (_fromStack)
return createFunction(functionName, [&]() {
return Whiskers(R"(
- function <functionName>(addr_and_function_id, pos) {
- mstore(pos, <cleanExtFun>(addr_and_function_id))
+ function <functionName>(addr, function_id, pos) {
+ mstore(pos, <combineExtFun>(addr, function_id))
}
)")
("functionName", functionName)
- ("cleanExtFun", cleanupCombinedExternalFunctionIdFunction())
+ ("combineExtFun", combineExternalFunctionIdFunction())
.render();
});
- }
else
- {
return createFunction(functionName, [&]() {
return Whiskers(R"(
- function <functionName>(addr, function_id, pos) {
- mstore(pos, <combineExtFun>(addr, function_id))
+ function <functionName>(addr_and_function_id, pos) {
+ mstore(pos, <cleanExtFun>(addr_and_function_id))
}
)")
("functionName", functionName)
- ("combineExtFun", combineExternalFunctionIdFunction())
+ ("cleanExtFun", cleanupCombinedExternalFunctionIdFunction())
.render();
});
- }
}
string ABIFunctions::copyToMemoryFunction(bool _fromCalldata)
@@ -1212,10 +1208,7 @@ size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
if (t->isDynamicallyEncoded())
headSize += 0x20;
else
- {
- solAssert(t->calldataEncodedSize() > 0, "");
headSize += t->calldataEncodedSize();
- }
}
return headSize;
diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h
index de2a140a..e61f68bc 100644
--- a/libsolidity/codegen/ABIFunctions.h
+++ b/libsolidity/codegen/ABIFunctions.h
@@ -89,13 +89,13 @@ private:
/// @returns the name of the ABI encoding function with the given type
/// and queues the generation of the function to the requested functions.
- /// @param _compacted if true, the input value was just loaded from storage
+ /// @param _fromStack if false, the input value was just loaded from storage
/// or memory and thus might be compacted into a single slot (depending on the type).
std::string abiEncodingFunction(
Type const& _givenType,
Type const& _targetType,
bool _encodeAsLibraryTypes,
- bool _compacted
+ bool _fromStack
);
/// Part of @a abiEncodingFunction for array target type and given calldata array.
std::string abiEncodingFunctionCalldataArray(
@@ -143,7 +143,7 @@ private:
FunctionType const& _from,
Type const& _to,
bool _encodeAsLibraryTypes,
- bool _compacted
+ bool _fromStack
);
/// @returns a function that copies raw bytes of dynamic length from calldata
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp
index e17188c2..ce8cbb5f 100644
--- a/libsolidity/codegen/ArrayUtils.cpp
+++ b/libsolidity/codegen/ArrayUtils.cpp
@@ -291,8 +291,11 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
CompilerUtils utils(m_context);
unsigned baseSize = 1;
if (!_sourceType.isByteArray())
+ {
// We always pad the elements, regardless of _padToWordBoundaries.
baseSize = _sourceType.baseType()->calldataEncodedSize();
+ solAssert(baseSize >= 0x20, "");
+ }
if (_sourceType.location() == DataLocation::CallData)
{
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 429db532..74565ae4 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -251,13 +251,10 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
FunctionDefinition const* fallback = _contract.fallbackFunction();
eth::AssemblyItem notFound = m_context.newTag();
- // shortcut messages without data if we have many functions in order to be able to receive
- // ether with constant gas
- if (interfaceFunctions.size() > 5 || fallback)
- {
- m_context << Instruction::CALLDATASIZE << Instruction::ISZERO;
- m_context.appendConditionalJumpTo(notFound);
- }
+ // directly jump to fallback if the data is too short to contain a function selector
+ // also guards against short data
+ m_context << u256(4) << Instruction::CALLDATASIZE << Instruction::LT;
+ m_context.appendConditionalJumpTo(notFound);
// retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty())
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index c2bf0f5c..bb8c4a94 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -858,8 +858,15 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::MSTORE;
// Stack: memptr requested_length
// update free memory pointer
- m_context << Instruction::DUP1 << arrayType.baseType()->memoryHeadSize();
- m_context << Instruction::MUL << u256(32) << Instruction::ADD;
+ m_context << Instruction::DUP1;
+ // Stack: memptr requested_length requested_length
+ if (arrayType.isByteArray())
+ // Round up to multiple of 32
+ m_context << u256(31) << Instruction::ADD << u256(31) << Instruction::NOT << Instruction::AND;
+ else
+ m_context << arrayType.baseType()->memoryHeadSize() << Instruction::MUL;
+ // stacK: memptr requested_length data_size
+ m_context << u256(32) << Instruction::ADD;
m_context << Instruction::DUP3 << Instruction::ADD;
utils().storeFreeMemoryPointer();
// Stack: memptr requested_length
@@ -1714,6 +1721,9 @@ void ExpressionCompiler::appendExternalFunctionCall(
if (_functionType.gasSet())
m_context << dupInstruction(m_context.baseToCurrentStackOffset(gasStackPos));
+ else if (m_context.experimentalFeatureActive(ExperimentalFeature::V050))
+ // Send all gas (requires tangerine whistle EVM)
+ m_context << Instruction::GAS;
else
{
// send all gas except the amount needed to execute "SUB" and "CALL"
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index fd78e578..2d2f05ec 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -234,6 +234,16 @@ void SMTChecker::endVisit(BinaryOperation const& _op)
void SMTChecker::endVisit(FunctionCall const& _funCall)
{
+ solAssert(_funCall.annotation().kind != FunctionCallKind::Unset, "");
+ if (_funCall.annotation().kind != FunctionCallKind::FunctionCall)
+ {
+ m_errorReporter.warning(
+ _funCall.location(),
+ "Assertion checker does not yet implement this expression."
+ );
+ return;
+ }
+
FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
std::vector<ASTPointer<Expression const>> const args = _funCall.arguments();
@@ -484,10 +494,10 @@ void SMTChecker::createVariable(VariableDeclaration const& _varDecl, bool _setTo
{
solAssert(m_currentSequenceCounter.count(&_varDecl) == 0, "");
solAssert(m_nextFreeSequenceCounter.count(&_varDecl) == 0, "");
- solAssert(m_Variables.count(&_varDecl) == 0, "");
+ solAssert(m_variables.count(&_varDecl) == 0, "");
m_currentSequenceCounter[&_varDecl] = 0;
m_nextFreeSequenceCounter[&_varDecl] = 1;
- m_Variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
+ m_variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
setValue(_varDecl, _setToZero);
}
else
@@ -556,7 +566,7 @@ smt::Expression SMTChecker::maxValue(IntegerType const& _t)
smt::Expression SMTChecker::expr(Expression const& _e)
{
- if (!m_Expressions.count(&_e))
+ if (!m_expressions.count(&_e))
{
solAssert(_e.annotation().type, "");
switch (_e.annotation().type->category())
@@ -565,24 +575,24 @@ smt::Expression SMTChecker::expr(Expression const& _e)
{
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(_e.annotation().type.get()))
solAssert(!rational->isFractional(), "");
- m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
}
case Type::Category::Integer:
- m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
case Type::Category::Bool:
- m_Expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
break;
default:
solAssert(false, "Type not implemented.");
}
}
- return m_Expressions.at(&_e);
+ return m_expressions.at(&_e);
}
smt::Expression SMTChecker::var(Declaration const& _decl)
{
- solAssert(m_Variables.count(&_decl), "");
- return m_Variables.at(&_decl);
+ solAssert(m_variables.count(&_decl), "");
+ return m_variables.at(&_decl);
}
diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h
index d23fd201..faaac639 100644
--- a/libsolidity/formal/SMTChecker.h
+++ b/libsolidity/formal/SMTChecker.h
@@ -103,8 +103,8 @@ private:
std::shared_ptr<smt::SolverInterface> m_interface;
std::map<Declaration const*, int> m_currentSequenceCounter;
std::map<Declaration const*, int> m_nextFreeSequenceCounter;
- std::map<Expression const*, smt::Expression> m_Expressions;
- std::map<Declaration const*, smt::Expression> m_Variables;
+ std::map<Expression const*, smt::Expression> m_expressions;
+ std::map<Declaration const*, smt::Expression> m_variables;
ErrorReporter& m_errorReporter;
FunctionDefinition const* m_currentFunction = nullptr;
diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp
index cbd766fb..c627057a 100644
--- a/libsolidity/formal/SMTLib2Interface.cpp
+++ b/libsolidity/formal/SMTLib2Interface.cpp
@@ -64,6 +64,8 @@ void SMTLib2Interface::pop()
Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codomain)
{
+ solAssert(!m_variables.count(_name), "");
+ m_variables[_name] = SMTVariableType::Function;
write(
"(declare-fun |" +
_name +
@@ -78,12 +80,16 @@ Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codom
Expression SMTLib2Interface::newInteger(string _name)
{
+ solAssert(!m_variables.count(_name), "");
+ m_variables[_name] = SMTVariableType::Integer;
write("(declare-const |" + _name + "| Int)");
return SolverInterface::newInteger(move(_name));
}
Expression SMTLib2Interface::newBool(string _name)
{
+ solAssert(!m_variables.count(_name), "");
+ m_variables[_name] = SMTVariableType::Bool;
write("(declare-const |" + _name + "| Bool)");
return SolverInterface::newBool(std::move(_name));
}
@@ -145,7 +151,8 @@ string SMTLib2Interface::checkSatAndGetValuesCommand(vector<Expression> const& _
for (size_t i = 0; i < _expressionsToEvaluate.size(); i++)
{
auto const& e = _expressionsToEvaluate.at(i);
- // TODO they don't have to be ints...
+ solAssert(m_variables.count(e.name), "");
+ solAssert(m_variables[e.name] == SMTVariableType::Integer, "");
command += "(declare-const |EVALEXPR_" + to_string(i) + "| Int)\n";
command += "(assert (= |EVALEXPR_" + to_string(i) + "| " + toSExpr(e) + "))\n";
}
diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h
index 63188acd..e827449f 100644
--- a/libsolidity/formal/SMTLib2Interface.h
+++ b/libsolidity/formal/SMTLib2Interface.h
@@ -68,6 +68,14 @@ private:
ReadCallback::Callback m_queryCallback;
std::vector<std::string> m_accumulatedOutput;
+
+ enum class SMTVariableType {
+ Function,
+ Integer,
+ Bool
+ };
+
+ std::map<std::string,SMTVariableType> m_variables;
};
}
diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp
index 0ceed3a7..6111b2c8 100644
--- a/libsolidity/formal/Z3Interface.cpp
+++ b/libsolidity/formal/Z3Interface.cpp
@@ -73,28 +73,37 @@ void Z3Interface::addAssertion(Expression const& _expr)
pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _expressionsToEvaluate)
{
CheckResult result;
- switch (m_solver.check())
+ vector<string> values;
+ try
{
- case z3::check_result::sat:
- result = CheckResult::SATISFIABLE;
- break;
- case z3::check_result::unsat:
- result = CheckResult::UNSATISFIABLE;
- break;
- case z3::check_result::unknown:
- result = CheckResult::UNKNOWN;
- break;
- default:
- solAssert(false, "");
+ switch (m_solver.check())
+ {
+ case z3::check_result::sat:
+ result = CheckResult::SATISFIABLE;
+ break;
+ case z3::check_result::unsat:
+ result = CheckResult::UNSATISFIABLE;
+ break;
+ case z3::check_result::unknown:
+ result = CheckResult::UNKNOWN;
+ break;
+ default:
+ solAssert(false, "");
+ }
+
+ if (result != CheckResult::UNSATISFIABLE)
+ {
+ z3::model m = m_solver.get_model();
+ for (Expression const& e: _expressionsToEvaluate)
+ values.push_back(toString(m.eval(toZ3Expr(e))));
+ }
}
-
- vector<string> values;
- if (result != CheckResult::UNSATISFIABLE)
+ catch (z3::exception const&)
{
- z3::model m = m_solver.get_model();
- for (Expression const& e: _expressionsToEvaluate)
- values.push_back(toString(m.eval(toZ3Expr(e))));
+ result = CheckResult::ERROR;
+ values.clear();
}
+
return make_pair(result, values);
}
@@ -118,8 +127,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
{">=", 2},
{"+", 2},
{"-", 2},
- {"*", 2},
- {">=", 2}
+ {"*", 2}
};
string const& n = _expr.name;
if (m_functions.count(n))
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 51544f8a..5713256a 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -252,6 +252,14 @@ bool CompilerStack::parseAndAnalyze()
return parse() && analyze();
}
+bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) const
+{
+ return
+ m_requestedContractNames.empty() ||
+ m_requestedContractNames.count(_contract.fullyQualifiedName()) ||
+ m_requestedContractNames.count(_contract.name());
+}
+
bool CompilerStack::compile()
{
if (m_stackState < AnalysisSuccessful)
@@ -262,7 +270,8 @@ bool CompilerStack::compile()
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
- compileContract(*contract, compiledContracts);
+ if (isRequestedContract(*contract))
+ compileContract(*contract, compiledContracts);
this->link();
m_stackState = CompilationSuccessful;
return true;
@@ -738,22 +747,32 @@ void CompilerStack::compileContract(
}
}
+string const CompilerStack::lastContractName() const
+{
+ if (m_contracts.empty())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
+ // try to find some user-supplied contract
+ string contractName;
+ for (auto const& it: m_sources)
+ for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
+ if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
+ contractName = contract->fullyQualifiedName();
+ return contractName;
+}
+
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
{
if (m_contracts.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
- string contractName = _contractName;
- if (_contractName.empty())
- // try to find some user-supplied contract
- for (auto const& it: m_sources)
- for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
- if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
- contractName = contract->fullyQualifiedName();
- auto it = m_contracts.find(contractName);
+
+ auto it = m_contracts.find(_contractName);
+ if (it != m_contracts.end())
+ return it->second;
+
// To provide a measure of backward-compatibility, if a contract is not located by its
// fully-qualified name, a lookup will be attempted purely on the contract's name to see
// if anything will satisfy.
- if (it == m_contracts.end() && contractName.find(":") == string::npos)
+ if (_contractName.find(":") == string::npos)
{
for (auto const& contractEntry: m_contracts)
{
@@ -764,12 +783,13 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa
string foundName;
getline(ss, source, ':');
getline(ss, foundName, ':');
- if (foundName == contractName) return contractEntry.second;
+ if (foundName == _contractName)
+ return contractEntry.second;
}
- // If we get here, both lookup methods failed.
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
}
- return it->second;
+
+ // If we get here, both lookup methods failed.
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract \"" + _contractName + "\" not found."));
}
CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index f1bbae47..b377b3aa 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -116,6 +116,13 @@ public:
m_optimizeRuns = _runs;
}
+ /// Sets the list of requested contract names. If empty, no filtering is performed and every contract
+ /// found in the supplied sources is compiled. Names are cleared iff @a _contractNames is missing.
+ void setRequestedContractNames(std::set<std::string> const& _contractNames = std::set<std::string>{})
+ {
+ m_requestedContractNames = _contractNames;
+ }
+
/// @arg _metadataLiteralSources When true, store sources as literals in the contract metadata.
void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; }
@@ -148,10 +155,10 @@ public:
std::map<std::string, unsigned> sourceIndices() const;
/// @returns the previously used scanner, useful for counting lines during error reporting.
- Scanner const& scanner(std::string const& _sourceName = "") const;
+ Scanner const& scanner(std::string const& _sourceName) const;
/// @returns the parsed source unit with the supplied name.
- SourceUnit const& ast(std::string const& _sourceName = "") const;
+ SourceUnit const& ast(std::string const& _sourceName) const;
/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
/// line and columns are numbered starting from 1 with following order:
@@ -161,48 +168,51 @@ public:
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
+ /// @returns the name of the last contract.
+ std::string const lastContractName() const;
+
/// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
std::string const filesystemFriendlyName(std::string const& _contractName) const;
/// @returns the assembled object for a contract.
- eth::LinkerObject const& object(std::string const& _contractName = "") const;
+ eth::LinkerObject const& object(std::string const& _contractName) const;
/// @returns the runtime object for the contract.
- eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const;
+ eth::LinkerObject const& runtimeObject(std::string const& _contractName) const;
/// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL.
/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
/// substituted by the actual address. Note that this sequence starts end ends in three X
/// characters but can contain anything in between.
- eth::LinkerObject const& cloneObject(std::string const& _contractName = "") const;
+ eth::LinkerObject const& cloneObject(std::string const& _contractName) const;
/// @returns normal contract assembly items
- eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
+ eth::AssemblyItems const* assemblyItems(std::string const& _contractName) const;
/// @returns runtime contract assembly items
- eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
+ eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName) const;
/// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr
/// if the contract does not (yet) have bytecode.
- std::string const* sourceMapping(std::string const& _contractName = "") const;
+ std::string const* sourceMapping(std::string const& _contractName) const;
/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
/// if the contract does not (yet) have bytecode.
- std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
+ std::string const* runtimeSourceMapping(std::string const& _contractName) const;
/// @return a verbose text representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
- std::string assemblyString(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
+ std::string assemblyString(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
- Json::Value assemblyJSON(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
+ Json::Value assemblyJSON(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.
- Json::Value const& contractABI(std::string const& _contractName = "") const;
+ Json::Value const& contractABI(std::string const& _contractName) const;
/// @returns a JSON representing the contract's user documentation.
/// Prerequisite: Successful call to parse or compile.
@@ -259,6 +269,9 @@ private:
/// Helper function to return path converted strings.
std::string sanitizePath(std::string const& _path) const { return boost::filesystem::path(_path).generic_string(); }
+ /// @returns true if the contract is requested to be compiled.
+ bool isRequestedContract(ContractDefinition const& _contract) const;
+
/// Compile a single contract and put the result in @a _compiledContracts.
void compileContract(
ContractDefinition const& _contract,
@@ -266,8 +279,8 @@ private:
);
void link();
- Contract const& contract(std::string const& _contractName = "") const;
- Source const& source(std::string const& _sourceName = "") const;
+ Contract const& contract(std::string const& _contractName) const;
+ Source const& source(std::string const& _sourceName) const;
/// @returns the parsed contract with the supplied name. Throws an exception if the contract
/// does not exist.
@@ -297,6 +310,7 @@ private:
ReadCallback::Callback m_smtQuery;
bool m_optimize = false;
unsigned m_optimizeRuns = 200;
+ std::set<std::string> m_requestedContractNames;
std::map<std::string, h160> m_libraries;
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
/// "context:prefix=target"
diff --git a/libsolidity/interface/SourceReferenceFormatter.cpp b/libsolidity/interface/SourceReferenceFormatter.cpp
index 62d22999..aeafaf2d 100644
--- a/libsolidity/interface/SourceReferenceFormatter.cpp
+++ b/libsolidity/interface/SourceReferenceFormatter.cpp
@@ -49,6 +49,21 @@ void SourceReferenceFormatter::printSourceLocation(
if (startLine == endLine)
{
string line = scanner.lineAtPosition(_location->start);
+
+ int locationLength = endColumn - startColumn;
+ if (locationLength > 150)
+ {
+ line = line.substr(0, startColumn + 35) + " ... " + line.substr(endColumn - 35);
+ endColumn = startColumn + 75;
+ locationLength = 75;
+ }
+ if (line.length() > 150)
+ {
+ line = " ... " + line.substr(startColumn, locationLength) + " ... ";
+ startColumn = 5;
+ endColumn = startColumn + locationLength;
+ }
+
_stream << line << endl;
for_each(
line.cbegin(),
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index b4fbbef9..430739ac 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -92,6 +92,22 @@ Json::Value formatErrorWithException(
return formatError(_warning, _type, _component, message, formattedMessage, location);
}
+set<string> requestedContractNames(Json::Value const& _outputSelection)
+{
+ set<string> names;
+ for (auto const& sourceName: _outputSelection.getMemberNames())
+ {
+ for (auto const& contractName: _outputSelection[sourceName].getMemberNames())
+ {
+ /// Consider the "all sources" shortcuts as requesting everything.
+ if (contractName == "*" || contractName == "")
+ return set<string>();
+ names.insert((sourceName == "*" ? "" : sourceName) + ":" + contractName);
+ }
+ }
+ return names;
+}
+
/// Returns true iff @a _hash (hex with 0x prefix) is the Keccak256 hash of the binary data in @a _content.
bool hashMatchesContent(string const& _hash, string const& _content)
{
@@ -265,6 +281,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
Json::Value metadataSettings = settings.get("metadata", Json::Value());
m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool());
+ Json::Value outputSelection = settings.get("outputSelection", Json::Value());
+ m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection));
+
auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compilerStack.scanner(_sourceName); };
try
diff --git a/lllc/main.cpp b/lllc/main.cpp
index 912ce16a..5679bc2b 100644
--- a/lllc/main.cpp
+++ b/lllc/main.cpp
@@ -35,15 +35,15 @@ using namespace dev::solidity;
using namespace dev::eth;
static string const VersionString =
- string(ETH_PROJECT_VERSION) +
- (string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
- (string(SOL_VERSION_BUILDINFO).empty() ? "" : "+" + string(SOL_VERSION_BUILDINFO));
+ string(ETH_PROJECT_VERSION) +
+ (string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
+ (string(SOL_VERSION_BUILDINFO).empty() ? "" : "+" + string(SOL_VERSION_BUILDINFO));
static void help()
{
cout
<< "Usage lllc [OPTIONS] <file>" << endl
- << "Options:" << endl
+ << "Options:" << endl
<< " -b,--binary Parse, compile and assemble; output byte code in binary." << endl
<< " -x,--hex Parse, compile and assemble; output byte code in hex." << endl
<< " -a,--assembly Only parse and compile; show assembly." << endl
@@ -51,12 +51,12 @@ static void help()
<< " -o,--optimise Turn on/off the optimiser; off by default." << endl
<< " -h,--help Show this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl;
- exit(0);
+ exit(0);
}
static void version()
{
- cout << "LLLC, the Lovely Little Language Compiler " << endl;
+ cout << "LLLC, the Lovely Little Language Compiler" << endl;
cout << "Version: " << VersionString << endl;
exit(0);
}
@@ -118,39 +118,39 @@ int main(int argc, char** argv)
string src;
if (infile.empty())
- {
- string s;
- while (!cin.eof())
- {
- getline(cin, s);
- src.append(s);
- }
- }
+ src = readStandardInput();
else
- src = contentsString(infile);
+ src = readFileAsString(infile);
vector<string> errors;
if (src.empty())
+ {
errors.push_back("Empty file.");
+ }
else if (mode == Disassemble)
{
cout << disassemble(fromHex(src)) << endl;
}
else if (mode == Binary || mode == Hex)
{
- auto bs = compileLLL(src, optimise ? true : false, &errors, contentsString);
+ auto bs = compileLLL(src, optimise ? true : false, &errors, readFileAsString);
if (mode == Hex)
cout << toHex(bs) << endl;
else if (mode == Binary)
cout.write((char const*)bs.data(), bs.size());
}
else if (mode == ParseTree)
+ {
cout << parseLLL(src) << endl;
+ }
else if (mode == Assembly)
- cout << compileLLLToAsm(src, optimise ? true : false, &errors, contentsString) << endl;
+ {
+ cout << compileLLLToAsm(src, optimise ? true : false, &errors, readFileAsString) << endl;
+ }
+
for (auto const& i: errors)
cerr << i << endl;
- if ( errors.size() )
+ if (errors.size())
return 1;
return 0;
}
diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh
index 01dee81d..49f864a0 100755
--- a/scripts/install_deps.sh
+++ b/scripts/install_deps.sh
@@ -231,6 +231,7 @@ case $(uname -s) in
autoconf \
automake \
boost-devel \
+ boost-static \
cmake \
gcc \
gcc-c++ \
diff --git a/scripts/test_emscripten.sh b/scripts/test_emscripten.sh
index b01b33bb..4996e957 100755
--- a/scripts/test_emscripten.sh
+++ b/scripts/test_emscripten.sh
@@ -36,6 +36,10 @@ DIR=$(mktemp -d)
echo "Preparing solc-js..."
git clone --depth 1 https://github.com/ethereum/solc-js "$DIR"
cd "$DIR"
+ # disable "prepublish" script which downloads the latest version
+ # (we will replace it anyway and it is often incorrectly cached
+ # on travis)
+ npm config set script.prepublish ''
npm install
# Replace soljson with current build
diff --git a/scripts/tests.sh b/scripts/tests.sh
index bf3e3455..2b47c254 100755
--- a/scripts/tests.sh
+++ b/scripts/tests.sh
@@ -42,8 +42,9 @@ elif [ -z $CI ]; then
ETH_PATH="eth"
else
mkdir -p /tmp/test
- wget -O /tmp/test/eth https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/eth_byzantium
- test "$(shasum /tmp/test/eth)" = "6e16ae5e0a0079d85fd63fb43547be3c52410e7e /tmp/test/eth"
+ # Update hash below if binary is changed.
+ wget -q -O /tmp/test/eth https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/eth_byzantium2
+ test "$(shasum /tmp/test/eth)" = "4dc3f208475f622be7c8e53bee720e14cd254c6f /tmp/test/eth"
sync
chmod +x /tmp/test/eth
sync # Otherwise we might get a "text file busy" error
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index 271511d4..9e2cb77a 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -424,20 +424,13 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
continue;
}
- m_sourceCodes[infile.string()] = dev::contentsString(infile.string());
+ m_sourceCodes[infile.string()] = dev::readFileAsString(infile.string());
path = boost::filesystem::canonical(infile).string();
}
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
}
if (addStdin)
- {
- string s;
- while (!cin.eof())
- {
- getline(cin, s);
- m_sourceCodes[g_stdinFileName].append(s + '\n');
- }
- }
+ m_sourceCodes[g_stdinFileName] = dev::readStandardInput();
}
bool CommandLineInterface::parseLibraryOption(string const& _input)
@@ -447,7 +440,7 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
try
{
if (fs::is_regular_file(_input))
- data = contentsString(_input);
+ data = readFileAsString(_input);
}
catch (fs::filesystem_error const&)
{
@@ -698,7 +691,7 @@ bool CommandLineInterface::processInput()
return ReadCallback::Result{false, "Not a valid file."};
else
{
- auto contents = dev::contentsString(canonicalPath.string());
+ auto contents = dev::readFileAsString(canonicalPath.string());
m_sourceCodes[path.string()] = contents;
return ReadCallback::Result{true, contents};
}
@@ -716,19 +709,22 @@ 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(",")))
- m_allowedDirectories.push_back(boost::filesystem::path(path));
+ 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() == ".") {
+ filesystem_path.remove_filename();
+ }
+ m_allowedDirectories.push_back(filesystem_path);
+ }
}
if (m_args.count(g_argStandardJSON))
{
- string input;
- while (!cin.eof())
- {
- string tmp;
- getline(cin, tmp);
- input.append(tmp + "\n");
- }
+ string input = dev::readStandardInput();
StandardCompiler compiler(fileReader);
cout << compiler.compile(input) << endl;
return true;
@@ -942,9 +938,10 @@ void CommandLineInterface::handleAst(string const& _argStr)
for (auto const& sourceCode: m_sourceCodes)
asts.push_back(&m_compiler->ast(sourceCode.first));
map<ASTNode const*, eth::GasMeter::GasConsumption> gasCosts;
- if (m_compiler->runtimeAssemblyItems())
+ // FIXME: shouldn't this be done for every contract?
+ if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
gasCosts = GasEstimator::breakToStatementLevel(
- GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(), asts),
+ GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
asts
);
diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h
index cc25bea7..2c61c0a6 100644
--- a/test/ExecutionFramework.h
+++ b/test/ExecutionFramework.h
@@ -172,78 +172,13 @@ public:
{
return bytes();
}
+
//@todo might be extended in the future
template <class Arg>
static bytes encodeDyn(Arg const& _arg)
{
return encodeArgs(u256(0x20), u256(_arg.size()), _arg);
}
- class ContractInterface
- {
- public:
- ContractInterface(ExecutionFramework& _framework): m_framework(_framework) {}
-
- void setNextValue(u256 const& _value) { m_nextValue = _value; }
-
- protected:
- template <class... Args>
- bytes const& call(std::string const& _sig, Args const&... _arguments)
- {
- auto const& ret = m_framework.callContractFunctionWithValue(_sig, m_nextValue, _arguments...);
- m_nextValue = 0;
- return ret;
- }
-
- void callString(std::string const& _name, std::string const& _arg)
- {
- BOOST_CHECK(call(_name + "(string)", u256(0x20), _arg.length(), _arg).empty());
- }
-
- void callStringAddress(std::string const& _name, std::string const& _arg1, u160 const& _arg2)
- {
- BOOST_CHECK(call(_name + "(string,address)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
- }
-
- void callStringAddressBool(std::string const& _name, std::string const& _arg1, u160 const& _arg2, bool _arg3)
- {
- BOOST_CHECK(call(_name + "(string,address,bool)", u256(0x60), _arg2, _arg3, _arg1.length(), _arg1).empty());
- }
-
- void callStringBytes32(std::string const& _name, std::string const& _arg1, h256 const& _arg2)
- {
- BOOST_CHECK(call(_name + "(string,bytes32)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
- }
-
- u160 callStringReturnsAddress(std::string const& _name, std::string const& _arg)
- {
- bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
- BOOST_REQUIRE(ret.size() == 0x20);
- BOOST_CHECK(std::count(ret.begin(), ret.begin() + 12, 0) == 12);
- return u160(u256(h256(ret)));
- }
-
- std::string callAddressReturnsString(std::string const& _name, u160 const& _arg)
- {
- bytesConstRef const ret(&call(_name + "(address)", _arg));
- BOOST_REQUIRE(ret.size() >= 0x40);
- u256 offset(h256(ret.cropped(0, 0x20)));
- BOOST_REQUIRE_EQUAL(offset, 0x20);
- u256 len(h256(ret.cropped(0x20, 0x20)));
- BOOST_REQUIRE_EQUAL(ret.size(), 0x40 + ((len + 0x1f) / 0x20) * 0x20);
- return ret.cropped(0x40, size_t(len)).toString();
- }
-
- h256 callStringReturnsBytes32(std::string const& _name, std::string const& _arg)
- {
- bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
- BOOST_REQUIRE(ret.size() == 0x20);
- return h256(ret);
- }
-
- private:
- u256 m_nextValue;
- ExecutionFramework& m_framework;
- };
private:
template <class CppFunction, class... Args>
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index 768c8c4b..60aafc85 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -74,7 +74,10 @@ IPCSocket::IPCSocket(string const& _path): m_path(_path)
BOOST_FAIL("Error creating IPC socket object");
if (connect(m_socket, reinterpret_cast<struct sockaddr const*>(&saun), sizeof(struct sockaddr_un)) < 0)
+ {
+ close(m_socket);
BOOST_FAIL("Error connecting to IPC socket: " << _path);
+ }
#endif
}
@@ -236,7 +239,11 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
"0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
"0000000000000000000000000000000000000002": { "wei": "1", "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
"0000000000000000000000000000000000000003": { "wei": "1", "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
- "0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } }
+ "0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
+ "0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } },
+ "0000000000000000000000000000000000000006": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_add", "linear": { "base": 500, "word": 0 } } },
+ "0000000000000000000000000000000000000007": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_mul", "linear": { "base": 40000, "word": 0 } } },
+ "0000000000000000000000000000000000000008": { "wei": "1", "precompiled": { "name": "alt_bn128_pairing_product" } }
}
}
)";
@@ -333,22 +340,25 @@ Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const&
return result["result"];
}
+string const& RPCSession::accountCreate()
+{
+ m_accounts.push_back(personal_newAccount(""));
+ personal_unlockAccount(m_accounts.back(), "", 100000);
+ return m_accounts.back();
+}
+
string const& RPCSession::accountCreateIfNotExists(size_t _id)
{
- if (_id >= m_accounts.size())
- {
- m_accounts.push_back(personal_newAccount(""));
- personal_unlockAccount(m_accounts.back(), "", 100000);
- }
+ while ((_id + 1) > m_accounts.size())
+ accountCreate();
return m_accounts[_id];
}
RPCSession::RPCSession(const string& _path):
m_ipcSocket(_path)
{
- string account = personal_newAccount("");
- personal_unlockAccount(account, "", 100000);
- m_accounts.push_back(account);
+ accountCreate();
+ // This will pre-fund the accounts create prior.
test_setChainParams(m_accounts);
}
diff --git a/test/RPCSession.h b/test/RPCSession.h
index eae6a09c..63f1dd21 100644
--- a/test/RPCSession.h
+++ b/test/RPCSession.h
@@ -121,6 +121,7 @@ public:
Json::Value rpcCall(std::string const& _methodName, std::vector<std::string> const& _args = std::vector<std::string>(), bool _canFail = false);
std::string const& account(size_t _id) const { return m_accounts.at(_id); }
+ std::string const& accountCreate();
std::string const& accountCreateIfNotExists(size_t _id);
private:
diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp
index 73a5d1ed..c9c744af 100644
--- a/test/contracts/AuctionRegistrar.cpp
+++ b/test/contracts/AuctionRegistrar.cpp
@@ -24,6 +24,7 @@
#include <tuple>
#include <boost/test/unit_test.hpp>
#include <test/libsolidity/SolidityExecutionFramework.h>
+#include <test/contracts/ContractInterface.h>
using namespace std;
using namespace dev::test;
@@ -230,7 +231,6 @@ protected:
BOOST_REQUIRE(!m_output.empty());
}
- using ContractInterface = SolidityExecutionFramework::ContractInterface;
class RegistrarInterface: public ContractInterface
{
public:
diff --git a/test/contracts/ContractInterface.h b/test/contracts/ContractInterface.h
new file mode 100644
index 00000000..052b0db2
--- /dev/null
+++ b/test/contracts/ContractInterface.h
@@ -0,0 +1,99 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <boost/test/unit_test.hpp>
+#include <test/ExecutionFramework.h>
+
+#include <functional>
+
+namespace dev
+{
+namespace test
+{
+
+class ContractInterface
+{
+public:
+ ContractInterface(ExecutionFramework& _framework): m_framework(_framework) {}
+
+ void setNextValue(u256 const& _value) { m_nextValue = _value; }
+
+protected:
+ template <class... Args>
+ bytes const& call(std::string const& _sig, Args const&... _arguments)
+ {
+ auto const& ret = m_framework.callContractFunctionWithValue(_sig, m_nextValue, _arguments...);
+ m_nextValue = 0;
+ return ret;
+ }
+
+ void callString(std::string const& _name, std::string const& _arg)
+ {
+ BOOST_CHECK(call(_name + "(string)", u256(0x20), _arg.length(), _arg).empty());
+ }
+
+ void callStringAddress(std::string const& _name, std::string const& _arg1, u160 const& _arg2)
+ {
+ BOOST_CHECK(call(_name + "(string,address)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
+ }
+
+ void callStringAddressBool(std::string const& _name, std::string const& _arg1, u160 const& _arg2, bool _arg3)
+ {
+ BOOST_CHECK(call(_name + "(string,address,bool)", u256(0x60), _arg2, _arg3, _arg1.length(), _arg1).empty());
+ }
+
+ void callStringBytes32(std::string const& _name, std::string const& _arg1, h256 const& _arg2)
+ {
+ BOOST_CHECK(call(_name + "(string,bytes32)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
+ }
+
+ u160 callStringReturnsAddress(std::string const& _name, std::string const& _arg)
+ {
+ bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
+ BOOST_REQUIRE(ret.size() == 0x20);
+ BOOST_CHECK(std::count(ret.begin(), ret.begin() + 12, 0) == 12);
+ return u160(u256(h256(ret)));
+ }
+
+ std::string callAddressReturnsString(std::string const& _name, u160 const& _arg)
+ {
+ bytesConstRef const ret(&call(_name + "(address)", _arg));
+ BOOST_REQUIRE(ret.size() >= 0x40);
+ u256 offset(h256(ret.cropped(0, 0x20)));
+ BOOST_REQUIRE_EQUAL(offset, 0x20);
+ u256 len(h256(ret.cropped(0x20, 0x20)));
+ BOOST_REQUIRE_EQUAL(ret.size(), 0x40 + ((len + 0x1f) / 0x20) * 0x20);
+ return ret.cropped(0x40, size_t(len)).toString();
+ }
+
+ h256 callStringReturnsBytes32(std::string const& _name, std::string const& _arg)
+ {
+ bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
+ BOOST_REQUIRE(ret.size() == 0x20);
+ return h256(ret);
+ }
+
+private:
+ u256 m_nextValue;
+ ExecutionFramework& m_framework;
+};
+
+}
+} // end namespaces
+
diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp
index bbe603d4..90334ad6 100644
--- a/test/contracts/Wallet.cpp
+++ b/test/contracts/Wallet.cpp
@@ -559,24 +559,24 @@ BOOST_AUTO_TEST_CASE(multisig_value_transfer)
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(3), h256::AlignRight)) == encodeArgs());
// 4 owners, set required to 3
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
- // check that balance is and stays zero at destination address
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ Address destination = Address("0x5c6d6026d3fb35cd7175fd0054ae8df50d8f8b41");
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(1), 10 * ether);
m_sender = account(1);
- auto ophash = callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ auto ophash = callContractFunction("execute(address,uint256,bytes)", h256(destination, h256::AlignRight), 100, 0x60, 0x00);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(2), 10 * ether);
m_sender = account(2);
callContractFunction("confirm(bytes32)", ophash);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(3), 10 * ether);
m_sender = account(3);
callContractFunction("confirm(bytes32)", ophash);
// now it should go through
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 100);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 100);
}
BOOST_AUTO_TEST_CASE(revoke_addOwner)
@@ -622,30 +622,31 @@ BOOST_AUTO_TEST_CASE(revoke_transaction)
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// create a transaction
Address deployer = m_sender;
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ Address destination = Address("0x5c6d6026d3fb35cd7175fd0054ae8df50d8f8b41");
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(1), 10 * ether);
m_sender = account(1);
- auto opHash = callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ auto opHash = callContractFunction("execute(address,uint256,bytes)", h256(destination, h256::AlignRight), 100, 0x60, 0x00);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(2), 10 * ether);
m_sender = account(2);
callContractFunction("confirm(bytes32)", opHash);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(1), 10 * ether);
m_sender = account(1);
BOOST_REQUIRE(callContractFunction("revoke(bytes32)", opHash) == encodeArgs());
m_sender = deployer;
callContractFunction("confirm(bytes32)", opHash);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
m_sender = account(0);
sendEther(account(3), 10 * ether);
m_sender = account(3);
callContractFunction("confirm(bytes32)", opHash);
// now it should go through
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 100);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 100);
}
BOOST_AUTO_TEST_CASE(daylimit)
@@ -661,31 +662,32 @@ BOOST_AUTO_TEST_CASE(daylimit)
BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs());
// try to send tx over daylimit
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ Address destination = Address("0x5c6d6026d3fb35cd7175fd0054ae8df50d8f8b41");
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
sendEther(account(1), 10 * ether);
m_sender = account(1);
BOOST_REQUIRE(
- callContractFunction("execute(address,uint256,bytes)", h256(0x05), 150, 0x60, 0x00) !=
+ callContractFunction("execute(address,uint256,bytes)", h256(destination, h256::AlignRight), 150, 0x60, 0x00) !=
encodeArgs(u256(0))
);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
// try to send tx under daylimit by stranger
m_sender = account(0);
sendEther(account(4), 10 * ether);
m_sender = account(4);
BOOST_REQUIRE(
- callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) ==
+ callContractFunction("execute(address,uint256,bytes)", h256(destination, h256::AlignRight), 90, 0x60, 0x00) ==
encodeArgs(u256(0))
);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 0);
// now send below limit by owner
m_sender = account(0);
sendEther(account(1), 10 * ether);
BOOST_REQUIRE(
- callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) ==
+ callContractFunction("execute(address,uint256,bytes)", h256(destination, h256::AlignRight), 90, 0x60, 0x00) ==
encodeArgs(u256(0))
);
- BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 90);
+ BOOST_CHECK_EQUAL(balanceAt(destination), 90);
}
BOOST_AUTO_TEST_CASE(daylimit_constructor)
diff --git a/test/libevmasm/Optimiser.cpp b/test/libevmasm/Optimiser.cpp
index 9dc49581..0ab95b08 100644
--- a/test/libevmasm/Optimiser.cpp
+++ b/test/libevmasm/Optimiser.cpp
@@ -841,6 +841,20 @@ BOOST_AUTO_TEST_CASE(peephole_double_push)
);
}
+BOOST_AUTO_TEST_CASE(peephole_pop_calldatasize)
+{
+ AssemblyItems items{
+ u256(4),
+ Instruction::CALLDATASIZE,
+ Instruction::LT,
+ Instruction::POP
+ };
+ PeepholeOptimiser peepOpt(items);
+ for (size_t i = 0; i < 3; i++)
+ BOOST_CHECK(peepOpt.optimise());
+ BOOST_CHECK(items.empty());
+}
+
BOOST_AUTO_TEST_CASE(jumpdest_removal)
{
AssemblyItems items{
diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp
index 2d66bce1..ace97e15 100644
--- a/test/liblll/Compiler.cpp
+++ b/test/liblll/Compiler.cpp
@@ -24,6 +24,7 @@
#include <memory>
#include <boost/test/unit_test.hpp>
#include <liblll/Compiler.h>
+#include <libdevcore/FixedHash.h>
using namespace std;
@@ -37,9 +38,9 @@ namespace test
namespace
{
-bool successCompile(std::string const& _sourceCode)
+bool successCompile(string const& _sourceCode)
{
- std::vector<std::string> errors;
+ vector<string> errors;
bytes bytecode = eth::compileLLL(_sourceCode, false, &errors);
if (!errors.empty())
return false;
@@ -121,6 +122,533 @@ BOOST_AUTO_TEST_CASE(switch_inconsistent_return_count)
BOOST_CHECK(!successCompile(sourceCode));
}
+BOOST_AUTO_TEST_CASE(disallowed_asm_instructions)
+{
+ for (unsigned i = 1; i <= 32; i++)
+ BOOST_CHECK(!successCompile("(asm PUSH" + boost::lexical_cast<string>(i) + ")"));
+}
+
+BOOST_AUTO_TEST_CASE(disallowed_functional_asm_instructions)
+{
+ for (unsigned i = 1; i <= 32; i++)
+ BOOST_CHECK(!successCompile("(PUSH" + boost::lexical_cast<string>(i) + ")"));
+ for (unsigned i = 1; i <= 16; i++)
+ BOOST_CHECK(!successCompile("(DUP" + boost::lexical_cast<string>(i) + ")"));
+ for (unsigned i = 1; i <= 16; i++)
+ BOOST_CHECK(!successCompile("(SWAP" + boost::lexical_cast<string>(i) + ")"));
+ BOOST_CHECK(!successCompile("(JUMPDEST)"));
+}
+
+BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
+{
+ vector<string> opcodes_bytecode {
+ "00",
+ "6000600001",
+ "6000600002",
+ "6000600003",
+ "6000600004",
+ "6000600005",
+ "6000600006",
+ "6000600007",
+ "60006000600008",
+ "60006000600009",
+ "600060000a",
+ "600060000b",
+ "6000600010",
+ "6000600011",
+ "6000600012",
+ "6000600013",
+ "6000600014",
+ "600015",
+ "6000600016",
+ "6000600017",
+ "6000600018",
+ "600019",
+ "600060001a",
+ "6000600020",
+ "30",
+ "600031",
+ "32",
+ "33",
+ "34",
+ "600035",
+ "36",
+ "60006000600037",
+ "38",
+ "60006000600039",
+ "3a",
+ "60003b",
+ "60006000600060003c",
+ "3d",
+ "6000600060003e",
+ "600040",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "600050",
+ "600051",
+ "6000600052",
+ "6000600053",
+ "600054",
+ "6000600055",
+ "600056",
+ "6000600057",
+ "58",
+ "59",
+ "5a",
+ "60ff",
+ "61ffff",
+ "62ffffff",
+ "63ffffffff",
+ "64ffffffffff",
+ "65ffffffffffff",
+ "66ffffffffffffff",
+ "67ffffffffffffffff",
+ "68ffffffffffffffffff",
+ "69ffffffffffffffffffff",
+ "6affffffffffffffffffffff",
+ "6bffffffffffffffffffffffff",
+ "6cffffffffffffffffffffffffff",
+ "6dffffffffffffffffffffffffffff",
+ "6effffffffffffffffffffffffffffff",
+ "6fffffffffffffffffffffffffffffffff",
+ "70ffffffffffffffffffffffffffffffffff",
+ "71ffffffffffffffffffffffffffffffffffff",
+ "72ffffffffffffffffffffffffffffffffffffff",
+ "73ffffffffffffffffffffffffffffffffffffffff",
+ "74ffffffffffffffffffffffffffffffffffffffffff",
+ "75ffffffffffffffffffffffffffffffffffffffffffff",
+ "76ffffffffffffffffffffffffffffffffffffffffffffff",
+ "77ffffffffffffffffffffffffffffffffffffffffffffffff",
+ "78ffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "79ffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7affffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "60006000a0",
+ "600060006000a1",
+ "6000600060006000a2",
+ "60006000600060006000a3",
+ "600060006000600060006000a4",
+ "600060006000f0",
+ "6000600060006000600060006000f1",
+ "6000600060006000600060006000f2",
+ "60006000f3",
+ "600060006000600060006000f4",
+ "600060006000600060006000fa",
+ "60006000fd",
+ "fe",
+ "6000ff"
+ };
+
+ vector<string> opcodes_lll {
+ "{ (STOP) }",
+ "{ (ADD 0 0) }",
+ "{ (MUL 0 0) }",
+ "{ (SUB 0 0) }",
+ "{ (DIV 0 0) }",
+ "{ (SDIV 0 0) }",
+ "{ (MOD 0 0) }",
+ "{ (SMOD 0 0) }",
+ "{ (ADDMOD 0 0 0) }",
+ "{ (MULMOD 0 0 0) }",
+ "{ (EXP 0 0) }",
+ "{ (SIGNEXTEND 0 0) }",
+ "{ (LT 0 0) }",
+ "{ (GT 0 0) }",
+ "{ (SLT 0 0) }",
+ "{ (SGT 0 0) }",
+ "{ (EQ 0 0) }",
+ "{ (ISZERO 0) }",
+ "{ (AND 0 0) }",
+ "{ (OR 0 0) }",
+ "{ (XOR 0 0) }",
+ "{ (NOT 0) }",
+ "{ (BYTE 0 0) }",
+ "{ (KECCAK256 0 0) }",
+ "{ (ADDRESS) }",
+ "{ (BALANCE 0) }",
+ "{ (ORIGIN) }",
+ "{ (CALLER) }",
+ "{ (CALLVALUE) }",
+ "{ (CALLDATALOAD 0) }",
+ "{ (CALLDATASIZE) }",
+ "{ (CALLDATACOPY 0 0 0) }",
+ "{ (CODESIZE) }",
+ "{ (CODECOPY 0 0 0) }",
+ "{ (GASPRICE) }",
+ "{ (EXTCODESIZE 0) }",
+ "{ (EXTCODECOPY 0 0 0 0) }",
+ "{ (RETURNDATASIZE) }",
+ "{ (RETURNDATACOPY 0 0 0) }",
+ "{ (BLOCKHASH 0) }",
+ "{ (COINBASE) }",
+ "{ (TIMESTAMP) }",
+ "{ (NUMBER) }",
+ "{ (DIFFICULTY) }",
+ "{ (GASLIMIT) }",
+ "{ (POP 0) }",
+ "{ (MLOAD 0) }",
+ "{ (MSTORE 0 0) }",
+ "{ (MSTORE8 0 0) }",
+ "{ (SLOAD 0) }",
+ "{ (SSTORE 0 0) }",
+ "{ (JUMP 0) }",
+ "{ (JUMPI 0 0) }",
+ "{ (PC) }",
+ "{ (MSIZE) }",
+ "{ (GAS) }",
+ "{ 0xff }",
+ "{ 0xffff }",
+ "{ 0xffffff }",
+ "{ 0xffffffff }",
+ "{ 0xffffffffff }",
+ "{ 0xffffffffffff }",
+ "{ 0xffffffffffffff }",
+ "{ 0xffffffffffffffff }",
+ "{ 0xffffffffffffffffff }",
+ "{ 0xffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ (LOG0 0 0) }",
+ "{ (LOG1 0 0 0) }",
+ "{ (LOG2 0 0 0 0) }",
+ "{ (LOG3 0 0 0 0 0) }",
+ "{ (LOG4 0 0 0 0 0 0) }",
+ "{ (CREATE 0 0 0) }",
+ "{ (CALL 0 0 0 0 0 0 0) }",
+ "{ (CALLCODE 0 0 0 0 0 0 0) }",
+ "{ (RETURN 0 0) }",
+ "{ (DELEGATECALL 0 0 0 0 0 0) }",
+ "{ (STATICCALL 0 0 0 0 0 0) }",
+ "{ (REVERT 0 0) }",
+ "{ (INVALID) }",
+ "{ (SELFDESTRUCT 0) }"
+ };
+
+ for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
+ vector<string> errors;
+ bytes code = eth::compileLLL(opcodes_lll[i], false, &errors);
+
+ BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]);
+
+ BOOST_CHECK_EQUAL(toHex(code), opcodes_bytecode[i]);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
+{
+ vector<string> opcodes_bytecode {
+ "00",
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ "08",
+ "09",
+ "0a",
+ "0b",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "1a",
+ "20",
+ "30",
+ "31",
+ "32",
+ "33",
+ "34",
+ "35",
+ "36",
+ "37",
+ "38",
+ "39",
+ "3a",
+ "3b",
+ "3c",
+ "3d",
+ "3e",
+ "40",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "50",
+ "51",
+ "52",
+ "53",
+ "54",
+ "55",
+ "56",
+ "57",
+ "58",
+ "59",
+ "5a",
+ "5b",
+ "60ff",
+ "61ffff",
+ "62ffffff",
+ "63ffffffff",
+ "64ffffffffff",
+ "65ffffffffffff",
+ "66ffffffffffffff",
+ "67ffffffffffffffff",
+ "68ffffffffffffffffff",
+ "69ffffffffffffffffffff",
+ "6affffffffffffffffffffff",
+ "6bffffffffffffffffffffffff",
+ "6cffffffffffffffffffffffffff",
+ "6dffffffffffffffffffffffffffff",
+ "6effffffffffffffffffffffffffffff",
+ "6fffffffffffffffffffffffffffffffff",
+ "70ffffffffffffffffffffffffffffffffff",
+ "71ffffffffffffffffffffffffffffffffffff",
+ "72ffffffffffffffffffffffffffffffffffffff",
+ "73ffffffffffffffffffffffffffffffffffffffff",
+ "74ffffffffffffffffffffffffffffffffffffffffff",
+ "75ffffffffffffffffffffffffffffffffffffffffffff",
+ "76ffffffffffffffffffffffffffffffffffffffffffffff",
+ "77ffffffffffffffffffffffffffffffffffffffffffffffff",
+ "78ffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "79ffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7affffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "80",
+ "81",
+ "82",
+ "83",
+ "84",
+ "85",
+ "86",
+ "87",
+ "88",
+ "89",
+ "8a",
+ "8b",
+ "8c",
+ "8d",
+ "8e",
+ "8f",
+ "90",
+ "91",
+ "92",
+ "93",
+ "94",
+ "95",
+ "96",
+ "97",
+ "98",
+ "99",
+ "9a",
+ "9b",
+ "9c",
+ "9d",
+ "9e",
+ "9f",
+ "a0",
+ "a1",
+ "a2",
+ "a3",
+ "a4",
+ "f0",
+ "f1",
+ "f2",
+ "f3",
+ "f4",
+ "fa",
+ "fd",
+ "fe",
+ "ff"
+ };
+
+ vector<string> opcodes_lll {
+ "{ (asm STOP) }",
+ "{ (asm ADD) }",
+ "{ (asm MUL) }",
+ "{ (asm SUB) }",
+ "{ (asm DIV) }",
+ "{ (asm SDIV ) }",
+ "{ (asm MOD) }",
+ "{ (asm SMOD) }",
+ "{ (asm ADDMOD) }",
+ "{ (asm MULMOD) }",
+ "{ (asm EXP) }",
+ "{ (asm SIGNEXTEND) }",
+ "{ (asm LT) }",
+ "{ (asm GT) }",
+ "{ (asm SLT) }",
+ "{ (asm SGT) }",
+ "{ (asm EQ) }",
+ "{ (asm ISZERO) }",
+ "{ (asm AND) }",
+ "{ (asm OR) }",
+ "{ (asm XOR) }",
+ "{ (asm NOT) }",
+ "{ (asm BYTE) }",
+ "{ (asm KECCAK256) }",
+ "{ (asm ADDRESS) }",
+ "{ (asm BALANCE) }",
+ "{ (asm ORIGIN) }",
+ "{ (asm CALLER) }",
+ "{ (asm CALLVALUE) }",
+ "{ (asm CALLDATALOAD) }",
+ "{ (asm CALLDATASIZE) }",
+ "{ (asm CALLDATACOPY) }",
+ "{ (asm CODESIZE) }",
+ "{ (asm CODECOPY) }",
+ "{ (asm GASPRICE) }",
+ "{ (asm EXTCODESIZE)}",
+ "{ (asm EXTCODECOPY) }",
+ "{ (asm RETURNDATASIZE) }",
+ "{ (asm RETURNDATACOPY) }",
+ "{ (asm BLOCKHASH) }",
+ "{ (asm COINBASE) }",
+ "{ (asm TIMESTAMP) }",
+ "{ (asm NUMBER) }",
+ "{ (asm DIFFICULTY) }",
+ "{ (asm GASLIMIT) }",
+ "{ (asm POP) }",
+ "{ (asm MLOAD) }",
+ "{ (asm MSTORE) }",
+ "{ (asm MSTORE8) }",
+ "{ (asm SLOAD) }",
+ "{ (asm SSTORE) }",
+ "{ (asm JUMP ) }",
+ "{ (asm JUMPI ) }",
+ "{ (asm PC) }",
+ "{ (asm MSIZE) }",
+ "{ (asm GAS) }",
+ "{ (asm JUMPDEST) }",
+ "{ (asm 0xff) }",
+ "{ (asm 0xffff) }",
+ "{ (asm 0xffffff) }",
+ "{ (asm 0xffffffff) }",
+ "{ (asm 0xffffffffff) }",
+ "{ (asm 0xffffffffffff) }",
+ "{ (asm 0xffffffffffffff) }",
+ "{ (asm 0xffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm DUP1) }",
+ "{ (asm DUP2) }",
+ "{ (asm DUP3) }",
+ "{ (asm DUP4) }",
+ "{ (asm DUP5) }",
+ "{ (asm DUP6) }",
+ "{ (asm DUP7) }",
+ "{ (asm DUP8) }",
+ "{ (asm DUP9) }",
+ "{ (asm DUP10) }",
+ "{ (asm DUP11) }",
+ "{ (asm DUP12) }",
+ "{ (asm DUP13) }",
+ "{ (asm DUP14) }",
+ "{ (asm DUP15) }",
+ "{ (asm DUP16) }",
+ "{ (asm SWAP1) }",
+ "{ (asm SWAP2) }",
+ "{ (asm SWAP3) }",
+ "{ (asm SWAP4) }",
+ "{ (asm SWAP5) }",
+ "{ (asm SWAP6) }",
+ "{ (asm SWAP7) }",
+ "{ (asm SWAP8) }",
+ "{ (asm SWAP9) }",
+ "{ (asm SWAP10) }",
+ "{ (asm SWAP11) }",
+ "{ (asm SWAP12) }",
+ "{ (asm SWAP13) }",
+ "{ (asm SWAP14) }",
+ "{ (asm SWAP15) }",
+ "{ (asm SWAP16) }",
+ "{ (asm LOG0) }",
+ "{ (asm LOG1) }",
+ "{ (asm LOG2) }",
+ "{ (asm LOG3) }",
+ "{ (asm LOG4) }",
+ "{ (asm CREATE) }",
+ "{ (asm CALL) }",
+ "{ (asm CALLCODE) }",
+ "{ (asm RETURN) }",
+ "{ (asm DELEGATECALL) }",
+ "{ (asm STATICCALL) }",
+ "{ (asm REVERT) }",
+ "{ (asm INVALID) }",
+ "{ (asm SELFDESTRUCT) }"
+ };
+
+ for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
+ vector<string> errors;
+ bytes code = eth::compileLLL(opcodes_lll[i], false, &errors);
+
+ BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]);
+
+ BOOST_CHECK_EQUAL(toHex(code), opcodes_bytecode[i]);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/ABIEncoderTests.cpp b/test/libsolidity/ABIEncoderTests.cpp
index 05158601..af51edcc 100644
--- a/test/libsolidity/ABIEncoderTests.cpp
+++ b/test/libsolidity/ABIEncoderTests.cpp
@@ -462,6 +462,87 @@ BOOST_AUTO_TEST_CASE(structs)
)
}
+BOOST_AUTO_TEST_CASE(empty_struct)
+{
+ string sourceCode = R"(
+ contract C {
+ struct S { }
+ S s;
+ event e(uint16, S, uint16);
+ function f() returns (uint, S, uint) {
+ e(7, s, 8);
+ return (7, s, 8);
+ }
+ }
+ )";
+
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ bytes encoded = encodeArgs(7, 8);
+ BOOST_CHECK(callContractFunction("f()") == encoded);
+ REQUIRE_LOG_DATA(encoded);
+ )
+}
+
+BOOST_AUTO_TEST_CASE(structs2)
+{
+ string sourceCode = R"(
+ contract C {
+ enum E {A, B, C}
+ struct T { uint x; E e; uint8 y; }
+ struct S { C c; T[] t;}
+ function f() public returns (uint a, S[2] s1, S[] s2, uint b) {
+ a = 7;
+ b = 8;
+ s1[0].c = this;
+ s1[0].t = new T[](1);
+ s1[0].t[0].x = 0x11;
+ s1[0].t[0].e = E.B;
+ s1[0].t[0].y = 0x12;
+ s2 = new S[](2);
+ s2[1].c = C(0x1234);
+ s2[1].t = new T[](3);
+ s2[1].t[1].x = 0x21;
+ s2[1].t[1].e = E.C;
+ s2[1].t[1].y = 0x22;
+ }
+ }
+ )";
+
+ NEW_ENCODER(
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(
+ 7, 0x80, 0x1e0, 8,
+ // S[2] s1
+ 0x40,
+ 0x100,
+ // S s1[0]
+ u256(u160(m_contractAddress)),
+ 0x40,
+ // T s1[0].t
+ 1, // length
+ // s1[0].t[0]
+ 0x11, 1, 0x12,
+ // S s1[1]
+ 0, 0x40,
+ // T s1[1].t
+ 0,
+ // S[] s2 (0x1e0)
+ 2, // length
+ 0x40, 0xa0,
+ // S s2[0]
+ 0, 0x40, 0,
+ // S s2[1]
+ 0x1234, 0x40,
+ // s2[1].t
+ 3, // length
+ 0, 0, 0,
+ 0x21, 2, 0x22,
+ 0, 0, 0
+ ));
+ )
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index 3bdc40a0..ea9703ea 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -81,7 +81,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
}
}
- return make_pair(&m_compiler.ast(), firstError);
+ return make_pair(&m_compiler.ast(""), firstError);
}
SourceUnit const* AnalysisFramework::parseAndAnalyse(string const& _source)
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 56ac8cf5..358d3c72 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(location_test)
shared_ptr<string const> n = make_shared<string>("");
AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations =
- vector<SourceLocation>(18, SourceLocation(2, 75, n)) +
+ vector<SourceLocation>(24, SourceLocation(2, 75, n)) +
vector<SourceLocation>(32, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
vector<SourceLocation>(2, SourceLocation(58, 67, n)) +
diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp
index c2886f5b..86e8201b 100644
--- a/test/libsolidity/GasMeter.cpp
+++ b/test/libsolidity/GasMeter.cpp
@@ -51,8 +51,8 @@ public:
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
- AssemblyItems const* items = m_compiler.runtimeAssemblyItems("");
- ASTNode const& sourceUnit = m_compiler.ast();
+ AssemblyItems const* items = m_compiler.runtimeAssemblyItems(m_compiler.lastContractName());
+ ASTNode const& sourceUnit = m_compiler.ast("");
BOOST_REQUIRE(items != nullptr);
m_gasCosts = GasEstimator::breakToStatementLevel(
GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
@@ -64,13 +64,13 @@ public:
{
compileAndRun(_sourceCode);
auto state = make_shared<KnownState>();
- PathGasMeter meter(*m_compiler.assemblyItems());
+ PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName()));
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
- u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
+ u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
// costs for deployment
gas += bytecodeSize * GasCosts::createDataGas;
// costs for transaction
- gas += gasForTransaction(m_compiler.object().bytecode, true);
+ gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);
BOOST_REQUIRE(!gas.isInfinite);
BOOST_CHECK(gas.value == m_gasUsed);
@@ -91,7 +91,7 @@ public:
}
gas += GasEstimator::functionalEstimation(
- *m_compiler.runtimeAssemblyItems(),
+ *m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()),
_sig
);
BOOST_REQUIRE(!gas.isInfinite);
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
if (first->first->location().intersects(second->first->location()))
{
BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
- auto scannerFromSource = [&](string const&) -> Scanner const& { return m_compiler.scanner(); };
+ auto scannerFromSource = [&](string const& _sourceName) -> Scanner const& { return m_compiler.scanner(_sourceName); };
SourceReferenceFormatter::printSourceLocation(cout, &first->first->location(), scannerFromSource);
SourceReferenceFormatter::printSourceLocation(cout, &second->first->location(), scannerFromSource);
}
diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp
index d58f296f..8d712a80 100644
--- a/test/libsolidity/SMTChecker.cpp
+++ b/test/libsolidity/SMTChecker.cpp
@@ -79,6 +79,32 @@ BOOST_AUTO_TEST_CASE(simple_overflow)
CHECK_WARNING(text, "Overflow (resulting value larger than");
}
+BOOST_AUTO_TEST_CASE(warn_on_typecast)
+{
+ string text = R"(
+ contract C {
+ function f() public pure returns (uint) {
+ return uint8(1);
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Assertion checker does not yet implement this expression.");
+}
+
+BOOST_AUTO_TEST_CASE(warn_on_struct)
+{
+ string text = R"(
+ contract C {
+ struct A { uint a; uint b; }
+ function f() public pure returns (A) {
+ return A({ a: 1, b: 2 });
+ }
+ }
+ )";
+ /// Multiple warnings, should check for: Assertion checker does not yet implement this expression.
+ CHECK_WARNING_ALLOW_MULTI(text, "");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 42f7525f..33962730 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -46,7 +46,7 @@ public:
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
- Json::Value generatedInterface = m_compilerStack.contractABI("");
+ Json::Value generatedInterface = m_compilerStack.contractABI(m_compilerStack.lastContractName());
Json::Value expectedInterface;
BOOST_REQUIRE(m_reader.parse(_expectedInterfaceString, expectedInterface));
BOOST_CHECK_MESSAGE(
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 35916ec7..9a837113 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2899,6 +2899,25 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws)
ABI_CHECK(callContractFunction("f()"), encodeArgs(0));
}
+BOOST_AUTO_TEST_CASE(short_data_calls_fallback)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint public x;
+ // Signature is d88e0b00
+ function fow() { x = 3; }
+ function () { x = 2; }
+ }
+ )";
+ compileAndRun(sourceCode);
+ // should call fallback
+ sendMessage(asBytes("\xd8\x8e\x0b"), false, 0);
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(2));
+ // should call function
+ sendMessage(asBytes(string("\xd8\x8e\x0b") + string(1, 0)), false, 0);
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(3));
+}
+
BOOST_AUTO_TEST_CASE(event)
{
char const* sourceCode = R"(
@@ -7309,6 +7328,30 @@ BOOST_AUTO_TEST_CASE(create_memory_array)
ABI_CHECK(callContractFunction("f()"), encodeArgs(string("A"), u256(8), u256(4), string("B")));
}
+BOOST_AUTO_TEST_CASE(create_memory_array_allocation_size)
+{
+ // Check allocation size of byte array. Should be 32 plus length rounded up to next
+ // multiple of 32
+ char const* sourceCode = R"(
+ contract C {
+ function f() pure returns (uint d1, uint d2, uint d3) {
+ bytes memory b1 = new bytes(31);
+ bytes memory b2 = new bytes(32);
+ bytes memory b3 = new bytes(256);
+ bytes memory b4 = new bytes(31);
+ assembly {
+ d1 := sub(b2, b1)
+ d2 := sub(b3, b2)
+ d3 := sub(b4, b3)
+ }
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(0x40, 0x40, 0x20 + 256));
+}
+
+
BOOST_AUTO_TEST_CASE(memory_arrays_of_various_sizes)
{
// Computes binomial coefficients the chinese way
@@ -10176,6 +10219,307 @@ BOOST_AUTO_TEST_CASE(address_overload_resolution)
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(5)));
}
+BOOST_AUTO_TEST_CASE(snark)
+{
+ char const* sourceCode = R"(
+ library Pairing {
+ struct G1Point {
+ uint X;
+ uint Y;
+ }
+ // Encoding of field elements is: X[0] * z + X[1]
+ struct G2Point {
+ uint[2] X;
+ uint[2] Y;
+ }
+
+ /// @return the generator of G1
+ function P1() internal returns (G1Point) {
+ return G1Point(1, 2);
+ }
+
+ /// @return the generator of G2
+ function P2() internal returns (G2Point) {
+ return G2Point(
+ [11559732032986387107991004021392285783925812861821192530917403151452391805634,
+ 10857046999023057135944570762232829481370756359578518086990519993285655852781],
+ [4082367875863433681332203403145435568316851327593401208105741076214120093531,
+ 8495653923123431417604973247489272438418190587263600148770280649306958101930]
+ );
+ }
+
+ /// @return the negation of p, i.e. p.add(p.negate()) should be zero.
+ function negate(G1Point p) internal returns (G1Point) {
+ // The prime q in the base field F_q for G1
+ uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+ if (p.X == 0 && p.Y == 0)
+ return G1Point(0, 0);
+ return G1Point(p.X, q - (p.Y % q));
+ }
+
+ /// @return the sum of two points of G1
+ function add(G1Point p1, G1Point p2) internal returns (G1Point r) {
+ uint[4] memory input;
+ input[0] = p1.X;
+ input[1] = p1.Y;
+ input[2] = p2.X;
+ input[3] = p2.Y;
+ bool success;
+ assembly {
+ success := call(sub(gas, 2000), 6, 0, input, 0xc0, r, 0x60)
+ // Use "invalid" to make gas estimation work
+ switch success case 0 { invalid() }
+ }
+ require(success);
+ }
+
+ /// @return the product of a point on G1 and a scalar, i.e.
+ /// p == p.mul(1) and p.add(p) == p.mul(2) for all points p.
+ function mul(G1Point p, uint s) internal returns (G1Point r) {
+ uint[3] memory input;
+ input[0] = p.X;
+ input[1] = p.Y;
+ input[2] = s;
+ bool success;
+ assembly {
+ success := call(sub(gas, 2000), 7, 0, input, 0x80, r, 0x60)
+ // Use "invalid" to make gas estimation work
+ switch success case 0 { invalid() }
+ }
+ require(success);
+ }
+
+ /// @return the result of computing the pairing check
+ /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
+ /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
+ /// return true.
+ function pairing(G1Point[] p1, G2Point[] p2) internal returns (bool) {
+ require(p1.length == p2.length);
+ uint elements = p1.length;
+ uint inputSize = p1.length * 6;
+ uint[] memory input = new uint[](inputSize);
+ for (uint i = 0; i < elements; i++)
+ {
+ input[i * 6 + 0] = p1[i].X;
+ input[i * 6 + 1] = p1[i].Y;
+ input[i * 6 + 2] = p2[i].X[0];
+ input[i * 6 + 3] = p2[i].X[1];
+ input[i * 6 + 4] = p2[i].Y[0];
+ input[i * 6 + 5] = p2[i].Y[1];
+ }
+ uint[1] memory out;
+ bool success;
+ assembly {
+ success := call(sub(gas, 2000), 8, 0, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
+ // Use "invalid" to make gas estimation work
+ switch success case 0 { invalid() }
+ }
+ require(success);
+ return out[0] != 0;
+ }
+ function pairingProd2(G1Point a1, G2Point a2, G1Point b1, G2Point b2) internal returns (bool) {
+ G1Point[] memory p1 = new G1Point[](2);
+ G2Point[] memory p2 = new G2Point[](2);
+ p1[0] = a1;
+ p1[1] = b1;
+ p2[0] = a2;
+ p2[1] = b2;
+ return pairing(p1, p2);
+ }
+ function pairingProd3(
+ G1Point a1, G2Point a2,
+ G1Point b1, G2Point b2,
+ G1Point c1, G2Point c2
+ ) internal returns (bool) {
+ G1Point[] memory p1 = new G1Point[](3);
+ G2Point[] memory p2 = new G2Point[](3);
+ p1[0] = a1;
+ p1[1] = b1;
+ p1[2] = c1;
+ p2[0] = a2;
+ p2[1] = b2;
+ p2[2] = c2;
+ return pairing(p1, p2);
+ }
+ function pairingProd4(
+ G1Point a1, G2Point a2,
+ G1Point b1, G2Point b2,
+ G1Point c1, G2Point c2,
+ G1Point d1, G2Point d2
+ ) internal returns (bool) {
+ G1Point[] memory p1 = new G1Point[](4);
+ G2Point[] memory p2 = new G2Point[](4);
+ p1[0] = a1;
+ p1[1] = b1;
+ p1[2] = c1;
+ p1[3] = d1;
+ p2[0] = a2;
+ p2[1] = b2;
+ p2[2] = c2;
+ p2[3] = d2;
+ return pairing(p1, p2);
+ }
+ }
+
+ contract Test {
+ using Pairing for *;
+ struct VerifyingKey {
+ Pairing.G2Point A;
+ Pairing.G1Point B;
+ Pairing.G2Point C;
+ Pairing.G2Point gamma;
+ Pairing.G1Point gammaBeta1;
+ Pairing.G2Point gammaBeta2;
+ Pairing.G2Point Z;
+ Pairing.G1Point[] IC;
+ }
+ struct Proof {
+ Pairing.G1Point A;
+ Pairing.G1Point A_p;
+ Pairing.G2Point B;
+ Pairing.G1Point B_p;
+ Pairing.G1Point C;
+ Pairing.G1Point C_p;
+ Pairing.G1Point K;
+ Pairing.G1Point H;
+ }
+ function f() returns (bool) {
+ Pairing.G1Point memory p1;
+ Pairing.G1Point memory p2;
+ p1.X = 1; p1.Y = 2;
+ p2.X = 1; p2.Y = 2;
+ var explict_sum = Pairing.add(p1, p2);
+ var scalar_prod = Pairing.mul(p1, 2);
+ return (explict_sum.X == scalar_prod.X &&
+ explict_sum.Y == scalar_prod.Y);
+ }
+ function g() returns (bool) {
+ Pairing.G1Point memory x = Pairing.add(Pairing.P1(), Pairing.negate(Pairing.P1()));
+ // should be zero
+ return (x.X == 0 && x.Y == 0);
+ }
+ function testMul() returns (bool) {
+ Pairing.G1Point memory p;
+ // @TODO The points here are reported to be not well-formed
+ p.X = 14125296762497065001182820090155008161146766663259912659363835465243039841726;
+ p.Y = 16229134936871442251132173501211935676986397196799085184804749187146857848057;
+ p = Pairing.mul(p, 13986731495506593864492662381614386532349950841221768152838255933892789078521);
+ return
+ p.X == 18256332256630856740336504687838346961237861778318632856900758565550522381207 &&
+ p.Y == 6976682127058094634733239494758371323697222088503263230319702770853579280803;
+ }
+ function pair() returns (bool) {
+ Pairing.G2Point memory fiveTimesP2 = Pairing.G2Point(
+ [4540444681147253467785307942530223364530218361853237193970751657229138047649, 20954117799226682825035885491234530437475518021362091509513177301640194298072],
+ [11631839690097995216017572651900167465857396346217730511548857041925508482915, 21508930868448350162258892668132814424284302804699005394342512102884055673846]
+ );
+ // The prime p in the base field F_p for G1
+ uint p = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
+ Pairing.G1Point[] memory g1points = new Pairing.G1Point[](2);
+ Pairing.G2Point[] memory g2points = new Pairing.G2Point[](2);
+ // check e(5 P1, P2)e(-P1, 5 P2) == 1
+ g1points[0] = Pairing.P1().mul(5);
+ g1points[1] = Pairing.P1().negate();
+ g2points[0] = Pairing.P2();
+ g2points[1] = fiveTimesP2;
+ if (!Pairing.pairing(g1points, g2points))
+ return false;
+ // check e(P1, P2)e(-P1, P2) == 1
+ g1points[0] = Pairing.P1();
+ g1points[1] = Pairing.P1();
+ g1points[1].Y = p - g1points[1].Y;
+ g2points[0] = Pairing.P2();
+ g2points[1] = Pairing.P2();
+ if (!Pairing.pairing(g1points, g2points))
+ return false;
+ return true;
+ }
+ function verifyingKey() internal returns (VerifyingKey vk) {
+ vk.A = Pairing.G2Point([0x209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7, 0x04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678], [0x2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d, 0x120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550]);
+ vk.B = Pairing.G1Point(0x2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc02, 0x03d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db84);
+ vk.C = Pairing.G2Point([0x2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb, 0x01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb3], [0x14a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713, 0x178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee24590]);
+ vk.gamma = Pairing.G2Point([0x25f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb1, 0x22acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d], [0x065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf68, 0x06d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb]);
+ vk.gammaBeta1 = Pairing.G1Point(0x15794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f21, 0x14db745c6780e9df549864cec19c2daf4531f6ec0c89cc1c7436cc4d8d300c6d);
+ vk.gammaBeta2 = Pairing.G2Point([0x1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e, 0x283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39], [0x140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e, 0x0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd4]);
+ vk.Z = Pairing.G2Point([0x217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac29, 0x0a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c], [0x26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a9855, 0x2fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d7]);
+ vk.IC = new Pairing.G1Point[](10);
+ vk.IC[0] = Pairing.G1Point(0x0aee46a7ea6e80a3675026dfa84019deee2a2dedb1bbe11d7fe124cb3efb4b5a, 0x044747b6e9176e13ede3a4dfd0d33ccca6321b9acd23bf3683a60adc0366ebaf);
+ vk.IC[1] = Pairing.G1Point(0x1e39e9f0f91fa7ff8047ffd90de08785777fe61c0e3434e728fce4cf35047ddc, 0x2e0b64d75ebfa86d7f8f8e08abbe2e7ae6e0a1c0b34d028f19fa56e9450527cb);
+ vk.IC[2] = Pairing.G1Point(0x1c36e713d4d54e3a9644dffca1fc524be4868f66572516025a61ca542539d43f, 0x042dcc4525b82dfb242b09cb21909d5c22643dcdbe98c4d082cc2877e96b24db);
+ vk.IC[3] = Pairing.G1Point(0x17d5d09b4146424bff7e6fb01487c477bbfcd0cdbbc92d5d6457aae0b6717cc5, 0x02b5636903efbf46db9235bbe74045d21c138897fda32e079040db1a16c1a7a1);
+ vk.IC[4] = Pairing.G1Point(0x0f103f14a584d4203c27c26155b2c955f8dfa816980b24ba824e1972d6486a5d, 0x0c4165133b9f5be17c804203af781bcf168da7386620479f9b885ecbcd27b17b);
+ vk.IC[5] = Pairing.G1Point(0x232063b584fb76c8d07995bee3a38fa7565405f3549c6a918ddaa90ab971e7f8, 0x2ac9b135a81d96425c92d02296322ad56ffb16299633233e4880f95aafa7fda7);
+ vk.IC[6] = Pairing.G1Point(0x09b54f111d3b2d1b2fe1ae9669b3db3d7bf93b70f00647e65c849275de6dc7fe, 0x18b2e77c63a3e400d6d1f1fbc6e1a1167bbca603d34d03edea231eb0ab7b14b4);
+ vk.IC[7] = Pairing.G1Point(0x0c54b42137b67cc268cbb53ac62b00ecead23984092b494a88befe58445a244a, 0x18e3723d37fae9262d58b548a0575f59d9c3266db7afb4d5739555837f6b8b3e);
+ vk.IC[8] = Pairing.G1Point(0x0a6de0e2240aa253f46ce0da883b61976e3588146e01c9d8976548c145fe6e4a, 0x04fbaa3a4aed4bb77f30ebb07a3ec1c7d77a7f2edd75636babfeff97b1ea686e);
+ vk.IC[9] = Pairing.G1Point(0x111e2e2a5f8828f80ddad08f9f74db56dac1cc16c1cb278036f79a84cf7a116f, 0x1d7d62e192b219b9808faa906c5ced871788f6339e8d91b83ac1343e20a16b30);
+ }
+ function verify(uint[] input, Proof proof) internal returns (uint) {
+ VerifyingKey memory vk = verifyingKey();
+ require(input.length + 1 == vk.IC.length);
+ // Compute the linear combination vk_x
+ Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
+ for (uint i = 0; i < input.length; i++)
+ vk_x = Pairing.add(vk_x, Pairing.mul(vk.IC[i + 1], input[i]));
+ vk_x = Pairing.add(vk_x, vk.IC[0]);
+ if (!Pairing.pairingProd2(proof.A, vk.A, Pairing.negate(proof.A_p), Pairing.P2())) return 1;
+ if (!Pairing.pairingProd2(vk.B, proof.B, Pairing.negate(proof.B_p), Pairing.P2())) return 2;
+ if (!Pairing.pairingProd2(proof.C, vk.C, Pairing.negate(proof.C_p), Pairing.P2())) return 3;
+ if (!Pairing.pairingProd3(
+ proof.K, vk.gamma,
+ Pairing.negate(Pairing.add(vk_x, Pairing.add(proof.A, proof.C))), vk.gammaBeta2,
+ Pairing.negate(vk.gammaBeta1), proof.B
+ )) return 4;
+ if (!Pairing.pairingProd3(
+ Pairing.add(vk_x, proof.A), proof.B,
+ Pairing.negate(proof.H), vk.Z,
+ Pairing.negate(proof.C), Pairing.P2()
+ )) return 5;
+ return 0;
+ }
+ event Verified(string);
+ function verifyTx() returns (bool) {
+ uint[] memory input = new uint[](9);
+ Proof memory proof;
+ proof.A = Pairing.G1Point(12873740738727497448187997291915224677121726020054032516825496230827252793177, 21804419174137094775122804775419507726154084057848719988004616848382402162497);
+ proof.A_p = Pairing.G1Point(7742452358972543465462254569134860944739929848367563713587808717088650354556, 7324522103398787664095385319014038380128814213034709026832529060148225837366);
+ proof.B = Pairing.G2Point(
+ [8176651290984905087450403379100573157708110416512446269839297438960217797614, 15588556568726919713003060429893850972163943674590384915350025440408631945055],
+ [15347511022514187557142999444367533883366476794364262773195059233657571533367, 4265071979090628150845437155927259896060451682253086069461962693761322642015]);
+ proof.B_p = Pairing.G1Point(2979746655438963305714517285593753729335852012083057917022078236006592638393, 6470627481646078059765266161088786576504622012540639992486470834383274712950);
+ proof.C = Pairing.G1Point(6851077925310461602867742977619883934042581405263014789956638244065803308498, 10336382210592135525880811046708757754106524561907815205241508542912494488506);
+ proof.C_p = Pairing.G1Point(12491625890066296859584468664467427202390981822868257437245835716136010795448, 13818492518017455361318553880921248537817650587494176379915981090396574171686);
+ proof.H = Pairing.G1Point(12091046215835229523641173286701717671667447745509192321596954139357866668225, 14446807589950902476683545679847436767890904443411534435294953056557941441758);
+ proof.K = Pairing.G1Point(21341087976609916409401737322664290631992568431163400450267978471171152600502, 2942165230690572858696920423896381470344658299915828986338281196715687693170);
+ input[0] = 13986731495506593864492662381614386532349950841221768152838255933892789078521;
+ input[1] = 622860516154313070522697309645122400675542217310916019527100517240519630053;
+ input[2] = 11094488463398718754251685950409355128550342438297986977413505294941943071569;
+ input[3] = 6627643779954497813586310325594578844876646808666478625705401786271515864467;
+ input[4] = 2957286918163151606545409668133310005545945782087581890025685458369200827463;
+ input[5] = 1384290496819542862903939282897996566903332587607290986044945365745128311081;
+ input[6] = 5613571677741714971687805233468747950848449704454346829971683826953541367271;
+ input[7] = 9643208548031422463313148630985736896287522941726746581856185889848792022807;
+ input[8] = 18066496933330839731877828156604;
+ if (verify(input, proof) == 0) {
+ Verified("Transaction successfully verified.");
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ }
+ )";
+ compileAndRun(sourceCode, 0, "Pairing");
+ compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Pairing", m_contractAddress}});
+ // Disabled because the point seems to be not well-formed, we need to find another example.
+ //BOOST_CHECK(callContractFunction("testMul()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("pair()") == encodeArgs(true));
+ BOOST_CHECK(callContractFunction("verifyTx()") == encodeArgs(true));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h
index 342d0875..b0daaba9 100644
--- a/test/libsolidity/SolidityExecutionFramework.h
+++ b/test/libsolidity/SolidityExecutionFramework.h
@@ -69,7 +69,7 @@ public:
);
BOOST_ERROR("Compiling contract failed");
}
- eth::LinkerObject obj = m_compiler.object(_contractName);
+ eth::LinkerObject obj = m_compiler.object(_contractName.empty() ? m_compiler.lastContractName() : _contractName);
BOOST_REQUIRE(obj.linkReferences.empty());
sendMessage(obj.bytecode + _arguments, true, _value);
return m_output;
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index ed223678..e5990e9b 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -4783,6 +4783,16 @@ BOOST_AUTO_TEST_CASE(warn_about_callcode)
}
)";
CHECK_WARNING(text, "\"callcode\" has been deprecated in favour of \"delegatecall\"");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ var x = address(0x12).callcode;
+ x;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "\"callcode\" has been deprecated in favour of \"delegatecall\"");
}
BOOST_AUTO_TEST_CASE(no_warn_about_callcode_as_function)
@@ -5537,7 +5547,7 @@ BOOST_AUTO_TEST_CASE(invalid_mobile_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid mobile type.");
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
}
BOOST_AUTO_TEST_CASE(warns_msg_value_in_non_payable_public_function)
@@ -5879,6 +5889,28 @@ BOOST_AUTO_TEST_CASE(interface_function_bodies)
CHECK_ERROR(text, TypeError, "Functions in interfaces cannot have an implementation");
}
+BOOST_AUTO_TEST_CASE(interface_function_external)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ interface I {
+ function f() external;
+ }
+ )";
+ success(text);
+}
+
+BOOST_AUTO_TEST_CASE(interface_function_public)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ interface I {
+ function f() public;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Functions in interfaces must be declared external.");
+}
+
BOOST_AUTO_TEST_CASE(interface_function_internal)
{
char const* text = R"(
@@ -6210,6 +6242,26 @@ BOOST_AUTO_TEST_CASE(warn_unused_return_parameter)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(no_unused_warning_interface_arguments)
+{
+ char const* text = R"(
+ interface I {
+ function f(uint a) pure public returns (uint b);
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(no_unused_warning_abstract_arguments)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint a) pure public returns (uint b);
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(no_unused_warnings)
{
char const* text = R"(
@@ -6371,6 +6423,17 @@ BOOST_AUTO_TEST_CASE(function_override_is_not_shadowing)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(event_parameter_cannot_shadow_state_variable)
+{
+ char const* text = R"(
+ contract C {
+ address a;
+ event E(address a);
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
BOOST_AUTO_TEST_CASE(callable_crash)
{
char const* text = R"(
@@ -6512,7 +6575,19 @@ BOOST_AUTO_TEST_CASE(warn_unspecified_storage)
}
}
)";
- CHECK_WARNING(text, "is declared as a storage pointer. Use an explicit \"storage\" keyword to silence this warning");
+ CHECK_WARNING(text, "Variable is declared as a storage pointer. Use an explicit \"storage\" keyword to silence this warning");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ struct S { uint a; }
+ S x;
+ function f() view public {
+ S y = x;
+ y;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Storage location must be specified as either \"memory\" or \"storage\".");
}
BOOST_AUTO_TEST_CASE(implicit_conversion_disallowed)
@@ -7031,6 +7106,53 @@ BOOST_AUTO_TEST_CASE(non_external_fallback)
CHECK_ERROR(text, TypeError, "Fallback function must be defined as \"external\".");
}
+BOOST_AUTO_TEST_CASE(invalid_literal_in_tuple)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure public {
+ uint x;
+ (x, ) = (1E111);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type");
+ text = R"(
+ contract C {
+ function f() pure public {
+ uint x;
+ (x, ) = (1, 1E111);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
+ text = R"(
+ contract C {
+ function f() pure public {
+ uint x;
+ (x, ) = (1E111, 1);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
+ text = R"(
+ contract C {
+ function f() pure public {
+ (2**270, 1);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
+ text = R"(
+ contract C {
+ function f() pure public {
+ ((2**270) / 2**100, 1);
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
BOOST_AUTO_TEST_CASE(warn_about_sha3)
{
char const* text = R"(
@@ -7079,7 +7201,7 @@ BOOST_AUTO_TEST_CASE(address_overload_resolution)
CHECK_SUCCESS(text);
}
-BOOST_AUTO_TEST_CASE(array_length_validation)
+BOOST_AUTO_TEST_CASE(array_length_too_large)
{
char const* text = R"(
contract C {
@@ -7089,6 +7211,108 @@ BOOST_AUTO_TEST_CASE(array_length_validation)
CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
}
+BOOST_AUTO_TEST_CASE(array_length_not_convertible_to_integer)
+{
+ char const* text = R"(
+ contract C {
+ uint[true] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
+{
+ char const* text = R"(
+ contract C {
+ uint[-true] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ text = R"(
+ contract C {
+ uint[true/1] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ text = R"(
+ contract C {
+ uint[1/true] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid constant expression.");
+ text = R"(
+ contract C {
+ uint[1.111111E1111111111111] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid literal value.");
+ text = R"(
+ contract C {
+ uint[3/0] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Operator / not compatible with types int_const 3 and int_const 0");
+}
+
+BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
+{
+ char const* text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() {
+ this.balance;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Member \"balance\" not found or not visible after argument-dependent lookup in contract");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() {
+ this.transfer;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Member \"transfer\" not found or not visible after argument-dependent lookup in contract");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() {
+ this.send;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Member \"send\" not found or not visible after argument-dependent lookup in contract");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() {
+ this.call;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Member \"call\" not found or not visible after argument-dependent lookup in contract");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() {
+ this.callcode;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Member \"callcode\" not found or not visible after argument-dependent lookup in contract");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() {
+ this.delegatecall;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Member \"delegatecall\" not found or not visible after argument-dependent lookup in contract");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp
index d83773bc..fb09451f 100644
--- a/test/libsolidity/SolidityNatspecJSON.cpp
+++ b/test/libsolidity/SolidityNatspecJSON.cpp
@@ -51,9 +51,9 @@ public:
Json::Value generatedDocumentation;
if (_userDocumentation)
- generatedDocumentation = m_compilerStack.natspecUser("");
+ generatedDocumentation = m_compilerStack.natspecUser(m_compilerStack.lastContractName());
else
- generatedDocumentation = m_compilerStack.natspecDev("");
+ generatedDocumentation = m_compilerStack.natspecDev(m_compilerStack.lastContractName());
Json::Value expectedDocumentation;
m_reader.parse(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index 24f915c0..4504946b 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -226,6 +226,183 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
);
}
+BOOST_AUTO_TEST_CASE(output_selection_explicit)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_all_contracts)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "fileA": {
+ "*": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_all_files_single_contract)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_all_files_all_contracts)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "*": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract A { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_dependent_contract)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "contract B { } contract A { function f() { new B(); } }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[{\"constant\":false,\"inputs\":[],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]");
+}
+
+BOOST_AUTO_TEST_CASE(output_selection_dependent_contract_with_import)
+{
+ char const* input = R"(
+ {
+ "language": "Solidity",
+ "settings": {
+ "outputSelection": {
+ "*": {
+ "A": [
+ "abi"
+ ]
+ }
+ }
+ },
+ "sources": {
+ "fileA": {
+ "content": "import \"fileB\"; contract A { function f() { new B(); } }"
+ },
+ "fileB": {
+ "content": "contract B { }"
+ }
+ }
+ }
+ )";
+ Json::Value result = compile(input);
+ BOOST_CHECK(containsAtMostWarnings(result));
+ Json::Value contract = getContractResult(result, "fileA", "A");
+ BOOST_CHECK(contract.isObject());
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK_EQUAL(dev::jsonCompactPrint(contract["abi"]), "[{\"constant\":false,\"inputs\":[],\"name\":\"f\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
index 80241519..6353ae8a 100644
--- a/test/libsolidity/ViewPureChecker.cpp
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -349,7 +349,7 @@ BOOST_AUTO_TEST_CASE(assembly)
assembly { x := 7 }
}
function g() view public {
- assembly { for {} 1 { pop(sload(0)) } { } }
+ assembly { for {} 1 { pop(sload(0)) } { } pop(gas) }
}
function h() view public {
assembly { function g() { pop(blockhash(20)) } }
@@ -357,6 +357,9 @@ BOOST_AUTO_TEST_CASE(assembly)
function j() public {
assembly { pop(call(0, 1, 2, 3, 4, 5, 6)) }
}
+ function k() public {
+ assembly { pop(call(gas, 1, 2, 3, 4, 5, 6)) }
+ }
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
@@ -367,7 +370,7 @@ BOOST_AUTO_TEST_CASE(assembly_staticcall)
string text = R"(
contract C {
function i() view public {
- assembly { pop(staticcall(0, 1, 2, 3, 4, 5)) }
+ assembly { pop(staticcall(gas, 1, 2, 3, 4, 5)) }
}
}
)";