aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml26
-rw-r--r--docs/contracts.rst12
-rw-r--r--docs/control-structures.rst15
-rw-r--r--docs/index.rst17
-rw-r--r--docs/introduction-to-smart-contracts.rst4
-rw-r--r--docs/miscellaneous.rst28
-rw-r--r--docs/security-considerations.rst221
-rw-r--r--docs/solidity-by-example.rst24
-rw-r--r--docs/types.rst7
-rwxr-xr-xfetch_umbrella_build_and_test.sh40
-rwxr-xr-xinstall_dependencies.sh107
-rw-r--r--libsolidity/analysis/TypeChecker.cpp26
-rw-r--r--libsolidity/analysis/TypeChecker.h3
-rw-r--r--test/CMakeLists.txt24
-rw-r--r--test/RPCSession.cpp262
-rw-r--r--test/RPCSession.h108
-rw-r--r--test/TestHelper.cpp59
-rw-r--r--test/TestHelper.h27
-rw-r--r--test/contracts/AuctionRegistrar.cpp105
-rw-r--r--test/contracts/CMakeLists.txt5
-rw-r--r--test/contracts/FixedFeeRegistrar.cpp47
-rw-r--r--test/contracts/Wallet.cpp131
-rw-r--r--test/libsolidity/CMakeLists.txt5
-rw-r--r--test/libsolidity/GasMeter.cpp19
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp159
-rw-r--r--test/libsolidity/SolidityExecutionFramework.cpp147
-rw-r--r--test/libsolidity/SolidityExecutionFramework.h (renamed from test/libsolidity/solidityExecutionFramework.h)75
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp73
-rw-r--r--test/libsolidity/SolidityOptimizer.cpp2
29 files changed, 1355 insertions, 423 deletions
diff --git a/.travis.yml b/.travis.yml
index 07458841..3a4115f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,15 @@
-# This is used to verify that the documentation compiles.
-language: python
-python:
- - "2.7"
-# command to install dependencies
-install: "pip install -q Sphinx==1.1.3 --use-mirrors"
-# command to run tests
-script: cd docs && sphinx-build -nW -b html -d _build/doctrees . _build/html
-# Flags used here, not in `make html`:
-# -n Run in nit-picky mode. Currently, this generates warnings for all missing references.
-# -W Turn warnings into errors. This means that the build stops at the first warning and sphinx-build exits with exit status 1.
+language: cpp
+cache: ccache
+matrix:
+ include:
+ - os: linux
+ dist: trusty
+ sudo: required
+ env: TRAVIS_BUILD_TYPE=Debug
+ - os: osx
+ osx_image: xcode7.3
+ env: TRAVIS_BUILD_TYPE=Debug
+git:
+ depth: 2
+before_install: ./install_dependencies.sh
+script: ./fetch_umbrella_build_and_test.sh \ No newline at end of file
diff --git a/docs/contracts.rst b/docs/contracts.rst
index 190750f9..c02c1490 100644
--- a/docs/contracts.rst
+++ b/docs/contracts.rst
@@ -356,7 +356,7 @@ all).
Furthermore, this function is executed whenever the contract receives plain
Ether (without data). In such a context, there is very little gas available to
-the function call, so it is important to make fallback functions as cheap as
+the function call (to be precise, 2300 gas), so it is important to make fallback functions as cheap as
possible.
::
@@ -883,8 +883,8 @@ custom types without the overhead of external function calls:
using BigInt for BigInt.bigint;
function f() {
- var x = bigint.fromUint(7);
- var y = bigint.fromUint(uint(-1));
+ var x = BigInt.fromUint(7);
+ var y = BigInt.fromUint(uint(-1));
var z = x.add(y);
}
}
@@ -986,7 +986,7 @@ Let us rewrite the set example from the
It is also possible to extend elementary types in that way::
library Search {
- function indexOf(uint[] storage self, uint value) {
+ function indexOf(uint[] storage self, uint value) returns (uint) {
for (uint i = 0; i < self.length; i++)
if (self[i] == value) return i;
return uint(-1);
@@ -1004,8 +1004,8 @@ It is also possible to extend elementary types in that way::
function replace(uint _old, uint _new) {
// This performs the library function call
- uint index = data.find(_old);
- if (index == -1)
+ uint index = data.indexOf(_old);
+ if (index == uint(-1))
data.push(_new);
else
data[index] = _new;
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 6d334ca2..064996ac 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -69,6 +69,21 @@ this does not execute a constructor. We could also have used ``function setFeed(
only (locally) sets the value and amount of gas sent with the function call and only the
parentheses at the end perform the actual call.
+.. warning::
+ Any interaction with another contract imposes a potential danger, especially
+ if the source code of the contract is not known in advance. The current
+ contract hands over control to the called contract and that may potentially
+ do just about anything. Even if the called contract inherits from a known parent contract,
+ the inheriting contract is only required to have a correct interface. The
+ implementation of the contract, however, can be completely arbitrary and thus,
+ pose a danger. In addition, be prepared in case it calls into other contracts of
+ your system or even back into the calling contract before the first
+ call returns. This means
+ that the called contract can change state variables of the calling contract
+ via its functions. Write your functions in a way that, for example, calls to
+ external functions happen after any changes to state variables in your contract
+ so your contract is not vulnerable to a recursive call exploit.
+
Named Calls and Anonymous Function Parameters
---------------------------------------------
diff --git a/docs/index.rst b/docs/index.rst
index 61081e1c..940fe5e7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -3,7 +3,7 @@ Solidity
Solidity is a high-level language whose syntax is similar to that of JavaScript
and it is designed to compile to code for the Ethereum Virtual Machine.
-As you will see, it is quite easy to create contracts for voting,
+As you will see, it is possible to create contracts for voting,
crowdfunding, blind auctions, multi-signature wallets and more.
.. note::
@@ -44,7 +44,7 @@ Available Solidity Integrations
* `Package for SublimeText — Solidity language syntax <https://packagecontrol.io/packages/Ethereum/>`_
Solidity syntax highlighting for SublimeText editor.
-* `Atom Solidity package <https://github.com/gmtcreators/atom-solidity/>`_
+* `Atom Ethereum interface <https://github.com/gmtDevs/atom-ethereum-interface>`_
Plugin for the Atom editor that features syntax highlighting, compilation and a runtime environment (requires backend node).
* `Atom Solidity Linter <https://atom.io/packages/linter-solidity>`_
@@ -59,6 +59,18 @@ Available Solidity Integrations
* `Vim Solidity <https://github.com/tomlion/vim-solidity/>`_
Plugin for the Vim editor providing syntax highlighting.
+Solidity Tools
+-------------------------------
+
+* `Solidity REPL <https://github.com/raineorshine/solidity-repl>`_
+ Try Solidity instantly with a command-line Solidity console.
+
+* `solgraph <https://github.com/raineorshine/solgraph>`_
+ Visualize Solidity control flow and highlight potential security vulnerabilities.
+
+* `evmdis <https://github.com/Arachnid/evmdis>`_
+ EVM Disassembler that performs static analysis on the bytecode to provide a higher level of abstraction than raw EVM operations.
+
Language Documentation
----------------------
@@ -92,6 +104,7 @@ Contents
installing-solidity.rst
solidity-by-example.rst
solidity-in-depth.rst
+ security-considerations.rst
style-guide.rst
common-patterns.rst
frequently-asked-questions.rst
diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst
index 0cb2b0d0..0122387b 100644
--- a/docs/introduction-to-smart-contracts.rst
+++ b/docs/introduction-to-smart-contracts.rst
@@ -136,12 +136,12 @@ single account.
.. index:: event
-The line ``event Sent(address from, address to, uint value);`` declares
+The line ``event Sent(address from, address to, uint amount);`` declares
a so-called "event" which is fired in the last line of the function
``send``. User interfaces (as well as server appliances of course) can
listen for those events being fired on the blockchain without much
cost. As soon as it is fired, the listener will also receive the
-arguments ``from``, ``to`` and ``value``, which makes it easy to track
+arguments ``from``, ``to`` and ``amount``, which makes it easy to track
transactions. In order to listen for this event, you would use ::
Coin.Sent().watch({}, '', function(error, result) {
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index c883815c..85fc286c 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -145,34 +145,6 @@ Tips and Tricks
* If you do **not** want your contracts to receive ether when called via ``send``, you can add a throwing fallback function ``function() { throw; }``.
* Initialise storage structs with a single assignment: ``x = MyStruct({a: 1, b: 2});``
-********
-Pitfalls
-********
-
-Unfortunately, there are some subtleties the compiler does not yet warn you about.
-
-- In ``for (var i = 0; i < arrayName.length; i++) { ... }``, the type of ``i`` will be ``uint8``, because this is the smallest type that is required to hold the value ``0``. If the array has more than 255 elements, the loop will not terminate.
-- If a contract receives Ether (without a function being called), the fallback function is executed. The contract can only rely
- on the "gas stipend" (2300 gas) being available to it at that time. This stipend is not enough to access storage in any way.
- To be sure that your contract can receive Ether in that way, check the gas requirements of the fallback function.
-- If you want to send ether using ``address.send``, there are certain details to be aware of:
-
- 1. If the recipient is a contract, it causes its fallback function to be executed which can in turn call back into the sending contract
- 2. Sending Ether can fail due to the call depth going above 1024. Since the caller is in total control of the call
- depth, they can force the transfer to fail, so make sure to always check the return value of ``send``. Better yet,
- write your contract using a pattern where the recipient can withdraw Ether instead.
- 3. Sending Ether can also fail because the recipient runs out of gas (either explicitly by using ``throw`` or
- because the operation is just too expensive). If the return value of ``send`` is checked, this might provide a
- means for the recipient to block progress in the sending contract. Again, the best practise here is to use
- a "withdraw" pattern instead of a "send" pattern.
-
-- Loops that do not have a fixed number of iterations, e.g. loops that depends on storage values, have to be used carefully:
- Due to the block gas limit, transactions can only consume a certain amount of gas. Either explicitly or just due to
- normal operation, the number of iterations in a loop can grow beyond the block gas limit, which can cause the complete
- contract to be stalled at a certain point. This does not apply at full extent to ``constant`` functions that are only executed
- to read data from the blockchain. Still, such functions may be called by other contracts as part of on-chain operations
- and stall those. Please be explicit about such cases in the documentation of your contracts.
-
**********
Cheatsheet
**********
diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst
new file mode 100644
index 00000000..f1a5dc03
--- /dev/null
+++ b/docs/security-considerations.rst
@@ -0,0 +1,221 @@
+#######################
+Security Considerations
+#######################
+
+While it is usually quite easy to build software that works as expected,
+it is much harder to check that nobody can use it in a way that was **not** anticipated.
+
+In Solidity, this is even more important because you can use smart contracts
+to handle tokens or, possibly, even more valuable things. Furthermore, every
+execution of a smart contract happens in public and, in addition to that,
+the source code is often available.
+
+Of course you always have to consider how much is at stake:
+You can compare a smart contract with a web service that is open to the
+public (and thus, also to malicous actors) and perhaps even open source.
+If you only store your grocery list on that web service, you might not have
+to take too much care, but if you manage your bank account using that web service,
+you should be more careful.
+
+This section will list some pitfalls and general security recommendations but
+can, of course, never be complete. Also, keep in mind that even if your
+smart contract code is bug-free, the compiler or the platform itself might
+have a bug.
+
+As always, with open source documentation, please help us extend this section
+(especially, some examples would not hurt)!
+
+********
+Pitfalls
+********
+
+Private Information and Randomness
+==================================
+
+Everything you use in a smart contract is publicly visible, even
+local variables and state variables marked ``private``.
+
+Using random numbers in smart contracts is quite tricky if you do not want
+miners to be able to cheat.
+
+Re-Entrancy
+===========
+
+Any interaction from a contract (A) with another contract (B) and any transfer
+of Ether hands over control to that contract (B). This makes it possible for B
+to call back into A before this interaction is completed. To give an example,
+the following code contains a bug (it is just a snippet and not a
+complete contract):
+
+::
+
+ // THIS CONTRACT CONTAINS A BUG - DO NOT USE
+ contract Fund {
+ /// Mapping of ether shares of the contract.
+ mapping(address => uint) shares;
+ /// Withdraw your share.
+ function withdraw() {
+ if (msg.sender.send(shares[msg.sender]))
+ shares[msg.sender] = 0;
+ }
+ }
+
+The problem is not too serious here because of the limited gas as part
+of ``send``, but it still exposes a weakness: Ether transfer always
+includes code execution, so the recipient could be a contract that calls
+back into ``withdraw``. This would let it get multiple refunds and
+basically retrieve all the Ether in the contract.
+
+To avoid re-entrancy, you can use the Checks-Effects-Interactions pattern as
+outlined further below:
+
+::
+
+ contract Fund {
+ /// Mapping of ether shares of the contract.
+ mapping(address => uint) shares;
+ /// Withdraw your share.
+ function withdraw() {
+ var share = shares[msg.sender];
+ shares[msg.sender] = 0;
+ if (!msg.sender.send(share))
+ throw;
+ }
+ }
+
+Note that re-entrancy is not only an effect of Ether transfer but of any
+function call on another contract. Furthermore, you also have to take
+multi-contract situations into account. A called contract could modify the
+state of another contract you depend on.
+
+Gas Limit and Loops
+===================
+
+Loops that do not have a fixed number of iterations, for example, loops that depend on storage values, have to be used carefully:
+Due to the block gas limit, transactions can only consume a certain amount of gas. Either explicitly or just due to
+normal operation, the number of iterations in a loop can grow beyond the block gas limit which can cause the complete
+contract to be stalled at a certain point. This may not apply to ``constant`` functions that are only executed
+to read data from the blockchain. Still, such functions may be called by other contracts as part of on-chain operations
+and stall those. Please be explicit about such cases in the documentation of your contracts.
+
+Sending and Receiving Ether
+===========================
+
+- If a contract receives Ether (without a function being called), the fallback function is executed. The contract can only rely
+ on the "gas stipend" (2300 gas) being available to it at that time. This stipend is not enough to access storage in any way.
+ To be sure that your contract can receive Ether in that way, check the gas requirements of the fallback function
+ (for example in the "details" section in browser-solidity).
+
+- There is a way to forward more gas to the receiving contract using
+ ``addr.call.value(x)()``. This is essentially the same as ``addr.send(x)``,
+ only that it forwards all remaining gas and opens up the ability for the
+ recipient to perform more expensive actions. This might include calling back
+ into the sending contract or other state changes you might not have though of.
+ So it allows for great flexibility for honest users but also for malicious actors.
+
+- If you want to send Ether using ``address.send``, there are certain details to be aware of:
+
+ 1. If the recipient is a contract, it causes its fallback function to be executed which can, in turn, call back the sending contract.
+ 2. Sending Ether can fail due to the call depth going above 1024. Since the caller is in total control of the call
+ depth, they can force the transfer to fail; make sure to always check the return value of ``send``. Better yet,
+ write your contract using a pattern where the recipient can withdraw Ether instead.
+ 3. Sending Ether can also fail because the execution of the recipient contract
+ requires more than the allotted amount of gas (explicitly by using ``throw`` or
+ because the operation is just too expensive) - it "runs out of gas" (OOG).
+ If the return value of ``send`` is checked, this might provide a
+ means for the recipient to block progress in the sending contract. Again, the best practice here is to use
+ a "withdraw" pattern instead of a "send" pattern.
+
+Callstack Depth
+===============
+
+External function calls can fail any time because they exceed the maximum
+call stack of 1024. In such situations, Solidity throws an exception.
+Malicious actors might be able to force the call stack to a high value
+before they interact with your contract.
+
+Note that ``.send()`` does **not** throw an exception if the call stack is
+depleted but rather returns ``false`` in that case. The low-level functions
+``.call()``, ``.callcode()`` and ``.delegatecall()`` behave in the same way.
+
+Minor Details
+=============
+
+- In ``for (var i = 0; i < arrayName.length; i++) { ... }``, the type of ``i`` will be ``uint8``, because this is the smallest type that is required to hold the value ``0``. If the array has more than 255 elements, the loop will not terminate.
+- The ``constant`` keyword for functions is currently not enforced by the compiler.
+ Furthermore, it is not enforced by the EVM, so a contract function that "claims"
+ to be constant might still cause changes to the state.
+- Types that do not occupy the full 32 bytes might contain "dirty higher order bits".
+ This is especially important if you access ``msg.data`` - it poses a malleability risk.
+
+***************
+Recommendations
+***************
+
+Restrict the Amount of Ether
+============================
+
+Restrict the amount of Ether (or other tokens) that can be stored in a smart
+contract. If your source code, the compiler or the platform has a bug, these
+funds may be lost. If you want to limit your loss, limit the amount of Ether.
+
+Keep it Small and Modular
+=========================
+
+Keep your contracts small and easily understandable. Single out unrelated
+functionality in other contracts or into libraries. General recommendations
+about source code quality of course apply: Limit the amount of local variables,
+the length of functions and so on. Document your functions so that others
+can see what your intention was and whether it is different than what the code does.
+
+Use the Checks-Effects-Interactions Pattern
+===========================================
+
+Most functions will first perform some checks (who called the function,
+are the arguments in range, did they send enough Ether, does the person
+have tokens, etc.). These checks should be done first.
+
+As the second step, if all checks passed, effects to the state variables
+of the current contract should be made. Interaction with other contracts
+should be the very last step in any function.
+
+Early contracts delayed some effects and waited for external function
+calls to return in a non-error state. This is often a serious mistake
+because of the re-entrancy problem explained above.
+
+Note that, also, calls to known contracts might in turn cause calls to
+unknown contracts, so it is probably better to just always apply this pattern.
+
+Include a Fail-Safe Mode
+========================
+
+While making your system fully decentralised will remove any intermediary,
+it might be a good idea, especially for new code, to include some kind
+of fail-safe mechanism:
+
+You can add a function in your smart contract that performs some
+self-checks like "Has any Ether leaked?",
+"Is the sum of the tokens equal to the balance of the contract?" or similar things.
+Keep in mind that you cannot use too much gas for that, so help through off-chain
+computations might be needed there.
+
+If the self-check fails, the contract automatically switches into some kind
+of "failsafe" mode, which, for example, disables most of the features, hands over
+control to a fixed and trusted third party or just converts the contract into
+a simple "give me back my money" contract.
+
+
+*******************
+Formal Verification
+*******************
+
+Using formal verification, it is possible to perform an automated mathematical
+proof that your source code fulfills a certain formal specification.
+The specification is still formal (just as the source code), but usually much
+simpler. There is a prototype in Solidity that performs formal verification and
+it will be better documented soon.
+
+Note that formal verification itself can only help you understand the
+difference between what you did (the specification) and how you did it
+(the actual implementation). You still need to check whether the specification
+is what you wanted and that you did not miss any unintended effects of it.
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index 6fa70be4..7dd51f00 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -291,15 +291,32 @@ activate themselves.
/// End the auction and send the highest bid
/// to the beneficiary.
function auctionEnd() {
+ // It is a good guideline to structure functions that interact
+ // with other contracts (i.e. they call functions or send Ether)
+ // into three phases:
+ // 1. checking conditions
+ // 2. performing actions (potentially changing conditions)
+ // 3. interacting with other contracts
+ // If these phases are mixed up, the other contract could call
+ // back into the current contract and modify the state or cause
+ // effects (ether payout) to be perfromed multiple times.
+ // If functions called internally include interaction with external
+ // contracts, they also have to be considered interaction with
+ // external contracts.
+
+ // 1. Conditions
if (now <= auctionStart + biddingTime)
throw; // auction did not yet end
if (ended)
throw; // this function has already been called
+
+ // 2. Effects
+ ended = true;
AuctionEnded(highestBidder, highestBid);
+ // 3. Interaction
if (!beneficiary.send(highestBid))
throw;
- ended = true;
}
function () {
@@ -476,7 +493,8 @@ high or low invalid bids.
var amount = pendingReturns[msg.sender];
// It is important to set this to zero because the recipient
// can call this function again as part of the receiving call
- // before `send` returns.
+ // before `send` returns (see the remark above about
+ // conditions -> effects -> interaction).
pendingReturns[msg.sender] = 0;
if (!msg.sender.send(amount))
throw; // If anything fails, this will revert the changes above
@@ -490,11 +508,11 @@ high or low invalid bids.
if (ended)
throw;
AuctionEnded(highestBidder, highestBid);
+ ended = true;
// We send all the money we have, because some
// of the refunds might have failed.
if (!beneficiary.send(this.balance))
throw;
- ended = true;
}
function () {
diff --git a/docs/types.rst b/docs/types.rst
index d7387ab3..50e86ed0 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -113,6 +113,13 @@ All three functions ``call``, ``delegatecall`` and ``callcode`` are very low-lev
All contracts inherit the members of address, so it is possible to query the balance of the
current contract using ``this.balance``.
+.. warning::
+ All these functions are low-level functions and should be used with care.
+ Specifically, any unknown contract might be malicious and if you call it, you
+ hand over control to that contract which could in turn call back into
+ your contract, so be prepared for changes to your state variables
+ when the call returns.
+
.. index:: byte array, bytes32
diff --git a/fetch_umbrella_build_and_test.sh b/fetch_umbrella_build_and_test.sh
new file mode 100755
index 00000000..ead54fea
--- /dev/null
+++ b/fetch_umbrella_build_and_test.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+set -ev
+
+if [[ "$OSTYPE" != "darwin"* ]]
+then
+ cd docs && sphinx-build -nW -b html -d _build/doctrees . _build/html && cd ..
+fi
+
+SUBREPO=solidity
+
+cd ..
+git clone --depth 3 -b develop https://github.com/ethereum/tests.git
+export ETHEREUM_TEST_PATH=$(pwd)/tests/
+git clone --recursive -b develop https://github.com/ethereum/webthree-umbrella.git
+cd webthree-umbrella
+rm -rf $SUBREPO
+mv ../$SUBREPO .
+mkdir build
+cd build
+OPTIONS=""
+if [[ "$OSTYPE" != "darwin"* ]]
+then
+ OPTIONS="-DCMAKE_C_COMPILER=/usr/lib/ccache/$CC -DCMAKE_CXX_COMPILER=/usr/lib/ccache/$CXX"
+fi
+cmake .. -DGUI=0 -DCMAKE_BUILD_TYPE=$TRAVIS_BUILD_TYPE $OPTIONS
+make lllc solc soljson soltest
+
+
+# Test runs disabled for macos for now,
+# we need to find a way to install eth.
+if [[ "$OSTYPE" != "darwin"* ]]
+then
+ eth --test -d /tmp/test &
+ while [ ! -S /tmp/test/geth.ipc ]; do sleep 2; done
+
+ ./solidity/test/soltest --ipc /tmp/test/geth.ipc
+ pkill eth
+fi
+
diff --git a/install_dependencies.sh b/install_dependencies.sh
new file mode 100755
index 00000000..737851b5
--- /dev/null
+++ b/install_dependencies.sh
@@ -0,0 +1,107 @@
+#!/usr/bin/env bash
+
+#------------------------------------------------------------------------------
+# Bash script for installing pre-requisite packages for cpp-ethereum.
+#
+# The documentation for cpp-ethereum is hosted at:
+#
+# http://www.ethdocs.org/en/latest/ethereum-clients/cpp-ethereum/
+#
+# (c) 2016 cpp-ethereum contributors.
+#------------------------------------------------------------------------------
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+
+ if echo `sw_vers` | grep "10.11"; then
+ echo OS X El Capitan detected
+ elif echo `sw_vers` | grep "10.10"; then
+ echo OS X Yosemite detected
+ else
+ echo Unsupported OS X version. We only support Yosemite and El Capitan.
+ exit 1
+ fi
+
+ brew update
+ brew upgrade
+
+ brew install boost
+ brew install cmake
+ brew install cryptopp
+ brew install miniupnpc
+ brew install leveldb
+ brew install gmp
+ brew install jsoncpp
+ brew install libmicrohttpd
+ brew install libjson-rpc-cpp
+ brew install homebrew/versions/llvm37
+
+elif [[ "$OSTYPE" == "linux-gnu" ]]; then
+
+ # NOTE - These steps are ONLY correct for Ubuntu Trusty. We need to add
+ # further conditionals in here for the other Ubuntu versions, and carry on
+ # from there if we then want to get this pattern working for Debian,
+ # OpenSUSE, Fedora, Arch Linux, Raspian, FreeBSD, etc.
+
+ # Add additional PPAs which we need to be able to build cpp-ethereum on
+ # Ubuntu Trusty. That includes our own PPAs and a PPA for getting CMake 3.x
+ # on Trusty.
+ sudo add-apt-repository -y ppa:ethereum/ethereum
+ sudo add-apt-repository -y ppa:ethereum/ethereum-dev
+ sudo apt-add-repository -y ppa:george-edison55/cmake-3.x
+ sudo apt-get -y update
+
+ # Install binaries for nearly all of our dependencies
+ sudo apt-get -y install \
+ python-sphinx \
+ build-essential \
+ cmake \
+ git \
+ libboost-all-dev \
+ libcurl4-openssl-dev \
+ libcryptopp-dev \
+ libgmp-dev \
+ libjsoncpp-dev \
+ libleveldb-dev \
+ libmicrohttpd-dev \
+ libminiupnpc-dev \
+ libz-dev \
+ opencl-headers \
+ eth
+
+ # The exception is libjson-rpc-cpp, which we have to build from source for
+ # reliable results. The only binaries available for this package are those
+ # we made ourselves against the (now very old) v0.4.2 release, which are unreliable,
+ # so instead we build the latest release label (v0.6.0) from source, which works just
+ # fine. We should update our PPA.
+ #
+ # See https://github.com/ethereum/webthree-umbrella/issues/513
+ #
+ # Hmm. Arachnid is still getting this issue on OS X, which already has v0.6.0, so
+ # it isn't as simple as just updating all our builds to that version, though that is
+ # sufficient for us to get CircleCI and TravisCI working. We still haven't got to
+ # the bottom of this issue, and are going to need to debug it in some scenario where
+ # we can reproduce it 100%, which MIGHT end up being within our automation here, but
+ # against a build-from-source-with-extra-printfs() of v0.4.2.
+ sudo apt-get -y install libargtable2-dev libedit-dev
+ git clone git://github.com/cinemast/libjson-rpc-cpp.git
+ cd libjson-rpc-cpp
+ git checkout v0.6.0
+ mkdir build
+ cd build
+ cmake .. -DCOMPILE_TESTS=NO
+ make
+ sudo make install
+ sudo ldconfig
+ cd ../..
+
+ # And install the English language package and reconfigure the locales.
+ # We really shouldn't need to do this, and should instead force our locales to "C"
+ # within our application runtimes, because this issue shows up on multiple Linux distros,
+ # and each will need fixing in the install steps, where we should really just fix it once
+ # in the code.
+ #
+ # See https://github.com/ethereum/webthree-umbrella/issues/169
+ sudo apt-get -y install language-pack-en-base
+ sudo dpkg-reconfigure locales
+
+fi
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index ce55de00..6b2c1cb8 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -830,6 +830,22 @@ void TypeChecker::endVisit(ExpressionStatement const& _statement)
if (type(_statement.expression())->category() == Type::Category::RationalNumber)
if (!dynamic_cast<RationalNumberType const&>(*type(_statement.expression())).mobileType())
typeError(_statement.expression().location(), "Invalid rational number.");
+
+ if (auto call = dynamic_cast<FunctionCall const*>(&_statement.expression()))
+ {
+ if (auto callType = dynamic_cast<FunctionType const*>(type(call->expression()).get()))
+ {
+ using Location = FunctionType::Location;
+ Location location = callType->location();
+ if (
+ location == Location::Bare ||
+ location == Location::BareCallCode ||
+ location == Location::BareDelegateCall ||
+ location == Location::Send
+ )
+ warning(_statement.location(), "Return value of low-level calls not used.");
+ }
+ }
}
bool TypeChecker::visit(Conditional const& _conditional)
@@ -1570,6 +1586,16 @@ void TypeChecker::typeError(SourceLocation const& _location, string const& _desc
m_errors.push_back(err);
}
+void TypeChecker::warning(SourceLocation const& _location, string const& _description)
+{
+ auto err = make_shared<Error>(Error::Type::Warning);
+ *err <<
+ errinfo_sourceLocation(_location) <<
+ errinfo_comment(_description);
+
+ m_errors.push_back(err);
+}
+
void TypeChecker::fatalTypeError(SourceLocation const& _location, string const& _description)
{
typeError(_location, _description);
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index 48f8285a..be1e02be 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -59,6 +59,9 @@ private:
/// Adds a new error to the list of errors.
void typeError(SourceLocation const& _location, std::string const& _description);
+ /// Adds a new warning to the list of errors.
+ void warning(SourceLocation const& _location, std::string const& _description);
+
/// Adds a new error to the list of errors and throws to abort type checking.
void fatalTypeError(SourceLocation const& _location, std::string const& _description);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ed53ce59..efcbb82e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,29 +1,11 @@
cmake_policy(SET CMP0015 NEW)
aux_source_directory(. SRC_LIST)
+aux_source_directory(contracts SRC_LIST)
+aux_source_directory(libsolidity SRC_LIST)
get_filename_component(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)
-macro (add_sources)
- file (RELATIVE_PATH _relPath ${TESTS_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
- foreach (_src ${ARGN})
- if (_relPath)
- list (APPEND SRC "${_relPath}/${_src}")
- else()
- list (APPEND SRC "${_src}")
- endif()
- endforeach()
- if (_relPath)
- # propagate SRCS to parent directory
- set (SRC ${SRC} PARENT_SCOPE)
- endif()
-endmacro()
-
-add_subdirectory(contracts)
-add_subdirectory(libsolidity)
-
-set(SRC_LIST ${SRC_LIST} ${SRC})
-
# search for test names and create ctest tests
enable_testing()
foreach(file ${SRC_LIST})
@@ -44,7 +26,7 @@ file(GLOB HEADERS "*.h" "*/*.h")
set(EXECUTABLE soltest)
eth_simple_add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS})
-eth_use(${EXECUTABLE} REQUIRED Solidity::solidity Eth::ethereum Eth::ethcore)
+eth_use(${EXECUTABLE} REQUIRED Solidity::solidity Eth::ethcore)
include_directories(BEFORE ..)
target_link_libraries(${EXECUTABLE} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
new file mode 100644
index 00000000..54e1675f
--- /dev/null
+++ b/test/RPCSession.cpp
@@ -0,0 +1,262 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file RPCSession.cpp
+ * @author Dimtiry Khokhlov <dimitry@ethdev.com>
+ * @date 2016
+ */
+
+#include <string>
+#include <stdio.h>
+#include <thread>
+#include <libdevcore/CommonData.h>
+#include <json/reader.h>
+#include <json/writer.h>
+#include "RPCSession.h"
+
+using namespace std;
+using namespace dev;
+
+IPCSocket::IPCSocket(string const& _path): m_path(_path)
+{
+ if (_path.length() >= sizeof(sockaddr_un::sun_path))
+ BOOST_FAIL("Error opening IPC: socket path is too long!");
+
+ struct sockaddr_un saun;
+ saun.sun_family = AF_UNIX;
+ strcpy(saun.sun_path, _path.c_str());
+
+ if ((m_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ BOOST_FAIL("Error creating IPC socket object");
+
+ int len = sizeof(saun.sun_family) + strlen(saun.sun_path);
+
+ if (connect(m_socket, reinterpret_cast<struct sockaddr const*>(&saun), len) < 0)
+ BOOST_FAIL("Error connecting to IPC socket: " << _path);
+
+ m_fp = fdopen(m_socket, "r");
+}
+
+string IPCSocket::sendRequest(string const& _req)
+{
+ send(m_socket, _req.c_str(), _req.length(), 0);
+
+ char c;
+ string response;
+ while ((c = fgetc(m_fp)) != EOF)
+ {
+ if (c != '\n')
+ response += c;
+ else
+ break;
+ }
+ return response;
+}
+
+RPCSession& RPCSession::instance(const string& _path)
+{
+ static RPCSession session(_path);
+ BOOST_REQUIRE_EQUAL(session.m_ipcSocket.path(), _path);
+ return session;
+}
+
+string RPCSession::eth_getCode(string const& _address, string const& _blockNumber)
+{
+ return rpcCall("eth_getCode", { quote(_address), quote(_blockNumber) }).asString();
+}
+
+RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string const& _transactionHash)
+{
+ TransactionReceipt receipt;
+ Json::Value const result = rpcCall("eth_getTransactionReceipt", { quote(_transactionHash) });
+ BOOST_REQUIRE(!result.isNull());
+ receipt.gasUsed = result["gasUsed"].asString();
+ receipt.contractAddress = result["contractAddress"].asString();
+ for (auto const& log: result["logs"])
+ {
+ LogEntry entry;
+ entry.address = log["address"].asString();
+ entry.data = log["data"].asString();
+ for (auto const& topic: log["topics"])
+ entry.topics.push_back(topic.asString());
+ receipt.logEntries.push_back(entry);
+ }
+ return receipt;
+}
+
+string RPCSession::eth_sendTransaction(TransactionData const& _td)
+{
+ return rpcCall("eth_sendTransaction", { _td.toJson() }).asString();
+}
+
+string RPCSession::eth_call(TransactionData const& _td, string const& _blockNumber)
+{
+ return rpcCall("eth_call", { _td.toJson(), quote(_blockNumber) }).asString();
+}
+
+string RPCSession::eth_sendTransaction(string const& _transaction)
+{
+ return rpcCall("eth_sendTransaction", { _transaction }).asString();
+}
+
+string RPCSession::eth_getBalance(string const& _address, string const& _blockNumber)
+{
+ string address = (_address.length() == 20) ? "0x" + _address : _address;
+ return rpcCall("eth_getBalance", { quote(address), quote(_blockNumber) }).asString();
+}
+
+string RPCSession::eth_getStorageRoot(string const& _address, string const& _blockNumber)
+{
+ string address = (_address.length() == 20) ? "0x" + _address : _address;
+ return rpcCall("eth_getStorageRoot", { quote(address), quote(_blockNumber) }).asString();
+}
+
+void RPCSession::personal_unlockAccount(string const& _address, string const& _password, int _duration)
+{
+ rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) });
+}
+
+string RPCSession::personal_newAccount(string const& _password)
+{
+ return rpcCall("personal_newAccount", { quote(_password) }).asString();
+}
+
+void RPCSession::test_setChainParams(vector<string> const& _accounts)
+{
+ static std::string const c_configString = R"(
+ {
+ "sealEngine": "NoProof",
+ "params": {
+ "accountStartNonce": "0x",
+ "maximumExtraDataSize": "0x1000000",
+ "blockReward": "0x",
+ "allowFutureBlocks": "1"
+ },
+ "genesis": {
+ "author": "0000000000000010000000000000000000000000",
+ "timestamp": "0x00",
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "extraData": "0x",
+ "gasLimit": "0x1000000000000"
+ },
+ "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 } } }
+ }
+ }
+ )";
+
+ Json::Value config;
+ BOOST_REQUIRE(Json::Reader().parse(c_configString, config));
+ for (auto const& account: _accounts)
+ config["accounts"][account]["wei"] = "0x100000000000000000000000000000000000000000";
+ test_setChainParams(Json::FastWriter().write(config));
+}
+
+void RPCSession::test_setChainParams(string const& _config)
+{
+ rpcCall("test_setChainParams", { _config });
+}
+
+void RPCSession::test_rewindToBlock(size_t _blockNr)
+{
+ rpcCall("test_rewindToBlock", { to_string(_blockNr) });
+}
+
+void RPCSession::test_mineBlocks(int _number)
+{
+ u256 startBlock = fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString()));
+ rpcCall("test_mineBlocks", { to_string(_number) }, true);
+
+ //@TODO do not use polling - but that would probably need a change to the test client
+ for (size_t polls = 0; polls < 100; ++polls)
+ {
+ if (fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())) >= startBlock + _number)
+ return;
+ std::this_thread::sleep_for(chrono::milliseconds(10)); //it does not work faster then 10 ms
+ }
+
+ BOOST_FAIL("Error in test_mineBlocks: block mining timeout!");
+}
+
+void RPCSession::test_modifyTimestamp(size_t _timestamp)
+{
+ rpcCall("test_modifyTimestamp", { to_string(_timestamp) });
+}
+
+Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const& _args, bool _canFail)
+{
+ string request = "{\"jsonrpc\":\"2.0\",\"method\":\"" + _methodName + "\",\"params\":[";
+ for (size_t i = 0; i < _args.size(); ++i)
+ {
+ request += _args[i];
+ if (i + 1 != _args.size())
+ request += ", ";
+ }
+
+ request += "],\"id\":" + to_string(m_rpcSequence) + "}";
+ ++m_rpcSequence;
+
+ //cout << "Request: " << request << endl;
+ string reply = m_ipcSocket.sendRequest(request);
+ //cout << "Reply: " << reply << endl;
+
+ Json::Value result;
+ Json::Reader().parse(reply, result, false);
+
+ if (result.isMember("error"))
+ {
+ if (_canFail)
+ return Json::Value();
+
+ BOOST_FAIL("Error on JSON-RPC call: " + result["error"]["message"].asString());
+ }
+ return result["result"];
+}
+
+string const& RPCSession::accountCreateIfNotExists(size_t _id)
+{
+ if (_id >= m_accounts.size())
+ {
+ m_accounts.push_back(personal_newAccount(""));
+ personal_unlockAccount(m_accounts.back(), "", 100000);
+ }
+ 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);
+ test_setChainParams(m_accounts);
+}
+
+string RPCSession::TransactionData::toJson() const
+{
+ Json::Value json;
+ json["from"] = (from.length() == 20) ? "0x" + from : from;
+ json["to"] = (to.length() == 20 || to == "") ? "0x" + to : to;
+ json["gas"] = gas;
+ json["gasprice"] = gasPrice;
+ json["value"] = value;
+ json["data"] = data;
+ return Json::FastWriter().write(json);
+
+}
diff --git a/test/RPCSession.h b/test/RPCSession.h
new file mode 100644
index 00000000..1a1fbbe5
--- /dev/null
+++ b/test/RPCSession.h
@@ -0,0 +1,108 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/** @file RPCSession.h
+ * @author Dimtiry Khokhlov <dimitry@ethdev.com>
+ * @date 2016
+ */
+
+#include <string>
+#include <stdio.h>
+#include <map>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <json/value.h>
+#include <boost/test/unit_test.hpp>
+
+class IPCSocket: public boost::noncopyable
+{
+public:
+ IPCSocket(std::string const& _path);
+ std::string sendRequest(std::string const& _req);
+ ~IPCSocket() { close(m_socket); fclose(m_fp); }
+
+ std::string const& path() const { return m_path; }
+
+private:
+ FILE *m_fp;
+ std::string m_path;
+ int m_socket;
+
+};
+
+class RPCSession: public boost::noncopyable
+{
+public:
+ struct TransactionData
+ {
+ std::string from;
+ std::string to;
+ std::string gas;
+ std::string gasPrice;
+ std::string value;
+ std::string data;
+
+ std::string toJson() const;
+ };
+
+ struct LogEntry {
+ std::string address;
+ std::vector<std::string> topics;
+ std::string data;
+ };
+
+ struct TransactionReceipt
+ {
+ std::string gasUsed;
+ std::string contractAddress;
+ std::vector<LogEntry> logEntries;
+ };
+
+ static RPCSession& instance(std::string const& _path);
+
+ std::string eth_getCode(std::string const& _address, std::string const& _blockNumber);
+ std::string eth_call(TransactionData const& _td, std::string const& _blockNumber);
+ TransactionReceipt eth_getTransactionReceipt(std::string const& _transactionHash);
+ std::string eth_sendTransaction(TransactionData const& _transactionData);
+ std::string eth_sendTransaction(std::string const& _transaction);
+ std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber);
+ std::string eth_getStorageRoot(std::string const& _address, std::string const& _blockNumber);
+ std::string personal_newAccount(std::string const& _password);
+ void personal_unlockAccount(std::string const& _address, std::string const& _password, int _duration);
+ void test_setChainParams(std::vector<std::string> const& _accounts);
+ void test_setChainParams(std::string const& _config);
+ void test_rewindToBlock(size_t _blockNr);
+ void test_modifyTimestamp(size_t _timestamp);
+ void test_mineBlocks(int _number);
+ 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& accountCreateIfNotExists(size_t _id);
+
+private:
+ RPCSession(std::string const& _path);
+
+ inline std::string quote(std::string const& _arg) { return "\"" + _arg + "\""; }
+ /// Parse std::string replacing keywords to values
+ void parseString(std::string& _string, std::map<std::string, std::string> const& _varMap);
+
+ IPCSocket m_ipcSocket;
+ size_t m_rpcSequence = 1;
+
+ std::vector<std::string> m_accounts;
+};
+
diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp
deleted file mode 100644
index 79242f83..00000000
--- a/test/TestHelper.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- This file is part of cpp-ethereum.
-
- cpp-ethereum 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.
-
- cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
-*/
-/** @file TestHelper.cpp
- * @author Marko Simovic <markobarko@gmail.com>
- * @date 2014
- */
-
-#include "TestHelper.h"
-
-using namespace std;
-
-namespace dev
-{
-namespace test
-{
-
-namespace
-{
- Listener* g_listener;
-}
-
-void Listener::registerListener(Listener& _listener)
-{
- g_listener = &_listener;
-}
-
-void Listener::notifySuiteStarted(std::string const& _name)
-{
- if (g_listener)
- g_listener->suiteStarted(_name);
-}
-
-void Listener::notifyTestStarted(std::string const& _name)
-{
- if (g_listener)
- g_listener->testStarted(_name);
-}
-
-void Listener::notifyTestFinished()
-{
- if (g_listener)
- g_listener->testFinished();
-}
-
-} } // namespaces
diff --git a/test/TestHelper.h b/test/TestHelper.h
index 96678007..2d08d62c 100644
--- a/test/TestHelper.h
+++ b/test/TestHelper.h
@@ -102,32 +102,5 @@ namespace test
} \
while (0)
-/// Allows observing test execution process.
-/// This class also provides methods for registering and notifying the listener
-class Listener
-{
-public:
- virtual ~Listener() = default;
-
- virtual void suiteStarted(std::string const&) {}
- virtual void testStarted(std::string const& _name) = 0;
- virtual void testFinished() = 0;
-
- static void registerListener(Listener& _listener);
- static void notifySuiteStarted(std::string const& _name);
- static void notifyTestStarted(std::string const& _name);
- static void notifyTestFinished();
-
- /// Test started/finished notification RAII helper
- class ExecTimeGuard
- {
- public:
- ExecTimeGuard(std::string const& _testName) { notifyTestStarted(_testName); }
- ~ExecTimeGuard() { notifyTestFinished(); }
- ExecTimeGuard(ExecTimeGuard const&) = delete;
- ExecTimeGuard& operator=(ExecTimeGuard) = delete;
- };
-};
-
}
}
diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp
index e13a79e0..9aa47189 100644
--- a/test/contracts/AuctionRegistrar.cpp
+++ b/test/contracts/AuctionRegistrar.cpp
@@ -25,7 +25,7 @@
#include <boost/test/unit_test.hpp>
#include <libdevcore/Hash.h>
#include <libethcore/ABI.h>
-#include <test/libsolidity/solidityExecutionFramework.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
using namespace std;
@@ -124,13 +124,19 @@ contract GlobalRegistrar is Registrar, AuctionSystem {
function onAuctionEnd(string _name) internal {
var auction = m_auctions[_name];
var record = m_toRecord[_name];
- if (record.owner != 0)
- record.owner.send(auction.sumOfBids - auction.highestBid / 100);
- else
- auction.highestBidder.send(auction.highestBid - auction.secondHighestBid);
+ var previousOwner = record.owner;
record.renewalDate = now + c_renewalInterval;
record.owner = auction.highestBidder;
Changed(_name);
+ if (previousOwner != 0) {
+ if (!record.owner.send(auction.sumOfBids - auction.highestBid / 100))
+ throw;
+ }
+ else
+ {
+ if (!auction.highestBidder.send(auction.highestBid - auction.secondHighestBid))
+ throw;
+ }
}
function reserve(string _name) external {
@@ -285,8 +291,8 @@ protected:
}
};
- u256 const m_biddingTime = u256(7 * 24 * 3600);
- u256 const m_renewalInterval = u256(365 * 24 * 3600);
+ size_t const m_biddingTime = size_t(7 * 24 * 3600);
+ size_t const m_renewalInterval = size_t(365 * 24 * 3600);
};
}
@@ -304,7 +310,6 @@ BOOST_AUTO_TEST_CASE(reserve)
// Test that reserving works for long strings
deployRegistrar();
vector<string> names{"abcabcabcabcabc", "defdefdefdefdef", "ghighighighighighighighighighighighighighighi"};
- m_sender = Address(0x123);
RegistrarInterface registrar(*this);
@@ -315,7 +320,7 @@ BOOST_AUTO_TEST_CASE(reserve)
for (auto const& name: names)
{
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), u160(0x123));
+ BOOST_CHECK_EQUAL(registrar.owner(name), u160(m_sender));
}
}
@@ -324,14 +329,14 @@ BOOST_AUTO_TEST_CASE(double_reserve_long)
// Test that it is not possible to re-reserve from a different address.
deployRegistrar();
string name = "abcabcabcabcabcabcabcabcabcabca";
- m_sender = Address(0x123);
RegistrarInterface registrar(*this);
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), u160(0x123));
+ BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
- m_sender = Address(0x124);
+ sendEther(account(1), u256(10) * eth::ether);
+ m_sender = account(1);
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), u160(0x123));
+ BOOST_CHECK_EQUAL(registrar.owner(name), account(0));
}
BOOST_AUTO_TEST_CASE(properties)
@@ -341,14 +346,17 @@ BOOST_AUTO_TEST_CASE(properties)
RegistrarInterface registrar(*this);
string names[] = {"abcaeouoeuaoeuaoeu", "defncboagufra,fui", "ghagpyajfbcuajouhaeoi"};
size_t addr = 0x9872543;
+ size_t count = 1;
for (string const& name: names)
{
- addr++;
- size_t sender = addr + 10007;
- m_sender = Address(sender);
+ m_sender = account(0);
+ sendEther(account(count), u256(20) * eth::ether);
+ m_sender = account(count);
+ auto sender = m_sender;
+ addr += count;
// setting by sender works
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), u160(sender));
+ BOOST_CHECK_EQUAL(registrar.owner(name), sender);
registrar.setAddress(name, addr, true);
BOOST_CHECK_EQUAL(registrar.addr(name), u160(addr));
registrar.setSubRegistrar(name, addr + 20);
@@ -357,14 +365,15 @@ BOOST_AUTO_TEST_CASE(properties)
BOOST_CHECK_EQUAL(registrar.content(name), h256(u256(addr + 90)));
// but not by someone else
- m_sender = Address(h256(addr + 10007 - 1));
- BOOST_CHECK_EQUAL(registrar.owner(name), u160(sender));
+ m_sender = account(count - 1);
+ BOOST_CHECK_EQUAL(registrar.owner(name), sender);
registrar.setAddress(name, addr + 1, true);
BOOST_CHECK_EQUAL(registrar.addr(name), u160(addr));
registrar.setSubRegistrar(name, addr + 20 + 1);
BOOST_CHECK_EQUAL(registrar.subRegistrar(name), u160(addr + 20));
registrar.setContent(name, h256(u256(addr + 90 + 1)));
BOOST_CHECK_EQUAL(registrar.content(name), h256(u256(addr + 90)));
+ count++;
}
}
@@ -372,7 +381,6 @@ BOOST_AUTO_TEST_CASE(transfer)
{
deployRegistrar();
string name = "abcaoeguaoucaeoduceo";
- m_sender = Address(0x123);
RegistrarInterface registrar(*this);
registrar.reserve(name);
registrar.setContent(name, h256(u256(123)));
@@ -385,7 +393,7 @@ BOOST_AUTO_TEST_CASE(disown)
{
deployRegistrar();
string name = "abcaoeguaoucaeoduceo";
- m_sender = Address(0x123);
+
RegistrarInterface registrar(*this);
registrar.reserve(name);
registrar.setContent(name, h256(u256(123)));
@@ -394,11 +402,12 @@ BOOST_AUTO_TEST_CASE(disown)
BOOST_CHECK_EQUAL(registrar.name(u160(124)), name);
// someone else tries disowning
- m_sender = Address(0x128);
+ sendEther(account(1), u256(10) * eth::ether);
+ m_sender = account(1);
registrar.disown(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x123);
+ BOOST_CHECK_EQUAL(registrar.owner(name), account(0));
- m_sender = Address(0x123);
+ m_sender = account(0);
registrar.disown(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
BOOST_CHECK_EQUAL(registrar.addr(name), 0);
@@ -411,78 +420,80 @@ BOOST_AUTO_TEST_CASE(auction_simple)
{
deployRegistrar();
string name = "x";
- m_sender = Address(0x123);
+
RegistrarInterface registrar(*this);
// initiate auction
registrar.setNextValue(8);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// "wait" until auction end
- m_envInfo.setTimestamp(m_envInfo.timestamp() + m_biddingTime + 10);
+ m_rpc.test_modifyTimestamp(currentTimestamp() + m_biddingTime + 10);
// trigger auction again
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x123);
+ BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
}
BOOST_AUTO_TEST_CASE(auction_bidding)
{
deployRegistrar();
string name = "x";
- m_sender = Address(0x123);
+
+ unsigned startTime = 0x776347e2;
+ m_rpc.test_modifyTimestamp(startTime);
+
RegistrarInterface registrar(*this);
// initiate auction
registrar.setNextValue(8);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// overbid self
- m_envInfo.setTimestamp(m_biddingTime - 10);
+ m_rpc.test_modifyTimestamp(startTime + m_biddingTime - 10);
registrar.setNextValue(12);
registrar.reserve(name);
// another bid by someone else
- m_sender = Address(0x124);
- m_envInfo.setTimestamp(2 * m_biddingTime - 50);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
+ m_rpc.test_modifyTimestamp(startTime + 2 * m_biddingTime - 50);
registrar.setNextValue(13);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// end auction by first bidder (which is not highest) trying to overbid again (too late)
- m_sender = Address(0x123);
- m_envInfo.setTimestamp(4 * m_biddingTime);
+ m_sender = account(0);
+ m_rpc.test_modifyTimestamp(startTime + 4 * m_biddingTime);
registrar.setNextValue(20);
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x124);
+ BOOST_CHECK_EQUAL(registrar.owner(name), account(1));
}
BOOST_AUTO_TEST_CASE(auction_renewal)
{
deployRegistrar();
+
string name = "x";
RegistrarInterface registrar(*this);
+ size_t startTime = currentTimestamp();
// register name by auction
- m_sender = Address(0x123);
registrar.setNextValue(8);
registrar.reserve(name);
- m_envInfo.setTimestamp(4 * m_biddingTime);
+ m_rpc.test_modifyTimestamp(startTime + 4 * m_biddingTime);
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x123);
+ BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
// try to re-register before interval end
- m_sender = Address(0x222);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
+ m_rpc.test_modifyTimestamp(currentTimestamp() + m_renewalInterval - 1);
registrar.setNextValue(80);
- m_envInfo.setTimestamp(m_envInfo.timestamp() + m_renewalInterval - 1);
registrar.reserve(name);
- m_envInfo.setTimestamp(m_envInfo.timestamp() + m_biddingTime);
- // if there is a bug in the renewal logic, this would transfer the ownership to 0x222,
+ m_rpc.test_modifyTimestamp(currentTimestamp() + m_biddingTime);
+ // if there is a bug in the renewal logic, this would transfer the ownership to account(1),
// but if there is no bug, this will initiate the auction, albeit with a zero bid
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x123);
+ BOOST_CHECK_EQUAL(registrar.owner(name), account(0));
- m_envInfo.setTimestamp(m_envInfo.timestamp() + 2);
registrar.setNextValue(80);
registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x123);
- m_envInfo.setTimestamp(m_envInfo.timestamp() + m_biddingTime + 2);
- registrar.reserve(name);
- BOOST_CHECK_EQUAL(registrar.owner(name), 0x222);
+ BOOST_CHECK_EQUAL(registrar.owner(name), account(1));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/contracts/CMakeLists.txt b/test/contracts/CMakeLists.txt
deleted file mode 100644
index 3ceda13b..00000000
--- a/test/contracts/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-cmake_policy(SET CMP0015 NEW)
-
-aux_source_directory(. SRCS)
-
-add_sources(${SRCS})
diff --git a/test/contracts/FixedFeeRegistrar.cpp b/test/contracts/FixedFeeRegistrar.cpp
index 796b3831..8cb8257a 100644
--- a/test/contracts/FixedFeeRegistrar.cpp
+++ b/test/contracts/FixedFeeRegistrar.cpp
@@ -33,7 +33,7 @@
#endif
#include <libdevcore/Hash.h>
-#include <test/libsolidity/solidityExecutionFramework.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
using namespace std;
@@ -81,7 +81,8 @@ contract FixedFeeRegistrar is Registrar {
}
function disown(string _name, address _refund) onlyrecordowner(_name) {
delete m_recordData[uint(sha3(_name)) / 8];
- _refund.send(c_fee);
+ if (!_refund.send(c_fee))
+ throw;
Changed(_name);
}
function transfer(string _name, address _newOwner) onlyrecordowner(_name) {
@@ -157,11 +158,10 @@ BOOST_AUTO_TEST_CASE(reserve)
// Test that reserving works and fee is taken into account.
deployRegistrar();
string name[] = {"abc", "def", "ghi"};
- m_sender = Address(0x123);
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name[0])) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[0])) == encodeArgs(h256(0x123)));
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[0])) == encodeArgs(h256(account(0), h256::AlignRight)));
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee + 1, encodeDyn(name[1])) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[1])) == encodeArgs(h256(0x123)));
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[1])) == encodeArgs(h256(account(0), h256::AlignRight)));
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee - 1, encodeDyn(name[2])) == encodeArgs());
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name[2])) == encodeArgs(h256(0)));
}
@@ -171,13 +171,13 @@ BOOST_AUTO_TEST_CASE(double_reserve)
// Test that it is not possible to re-reserve from a different address.
deployRegistrar();
string name = "abc";
- m_sender = Address(0x123);
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123)));
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(account(0), h256::AlignRight)));
- m_sender = Address(0x124);
+ sendEther(account(1), 100 * eth::ether);
+ m_sender = account(1);
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(0x123)));
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(account(0), h256::AlignRight)));
}
BOOST_AUTO_TEST_CASE(properties)
@@ -186,29 +186,36 @@ BOOST_AUTO_TEST_CASE(properties)
deployRegistrar();
string names[] = {"abc", "def", "ghi"};
size_t addr = 0x9872543;
+ size_t count = 1;
for (string const& name: names)
{
addr++;
- size_t sender = addr + 10007;
- m_sender = Address(sender);
+ m_sender = account(0);
+ sendEther(account(count), 100 * eth::ether);
+ m_sender = account(count);
+ Address owner = m_sender;
// setting by sender works
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(sender)));
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(owner, h256::AlignRight)));
BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(addr), u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr));
BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20, u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20));
BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90, u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90));
+ count++;
// but not by someone else
- m_sender = Address(h256(addr + 10007 - 1));
- BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(sender));
+ m_sender = account(0);
+ sendEther(account(count), 100 * eth::ether);
+ m_sender = account(count);
+ BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(h256(owner, h256::AlignRight)));
BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), addr + 1, u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("addr(string)", encodeDyn(name)) == encodeArgs(addr));
BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), addr + 20 + 1, u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("subRegistrar(string)", encodeDyn(name)) == encodeArgs(addr + 20));
BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), addr + 90 + 1, u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(addr + 90));
+ count++;
}
}
@@ -216,27 +223,25 @@ BOOST_AUTO_TEST_CASE(transfer)
{
deployRegistrar();
string name = "abc";
- m_sender = Address(0x123);
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), h256(account(0), h256::AlignRight), u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("transfer(string,address)", u256(0x40), u256(555), u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(555)));
- BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(123)));
+ BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(h256(account(0), h256::AlignRight)));
}
BOOST_AUTO_TEST_CASE(disown)
{
deployRegistrar();
string name = "abc";
- m_sender = Address(0x123);
BOOST_REQUIRE(callContractFunctionWithValue("reserve(string)", m_fee, encodeDyn(name)) == encodeArgs());
- BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), u256(123), u256(name.length()), name) == encodeArgs());
+ BOOST_CHECK(callContractFunction("setContent(string,bytes32)", u256(0x40), h256(account(0), h256::AlignRight), u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("setAddr(string,address)", u256(0x40), u256(124), u256(name.length()), name) == encodeArgs());
BOOST_CHECK(callContractFunction("setSubRegistrar(string,address)", u256(0x40), u256(125), u256(name.length()), name) == encodeArgs());
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x124)), 0);
BOOST_CHECK(callContractFunction("disown(string,address)", u256(0x40), u256(0x124), name.size(), name) == encodeArgs());
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x124)), m_fee);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x124)), m_fee);
BOOST_CHECK(callContractFunction("owner(string)", encodeDyn(name)) == encodeArgs(u256(0)));
BOOST_CHECK(callContractFunction("content(string)", encodeDyn(name)) == encodeArgs(u256(0)));
diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp
index 7c4a9a84..fbab2404 100644
--- a/test/contracts/Wallet.cpp
+++ b/test/contracts/Wallet.cpp
@@ -33,7 +33,7 @@
#endif
#include <libdevcore/Hash.h>
-#include <test/libsolidity/solidityExecutionFramework.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
using namespace std;
@@ -471,19 +471,22 @@ BOOST_AUTO_TEST_CASE(add_owners)
{
deployWallet(200);
Address originalOwner = m_sender;
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true));
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs(true));
// now let the new owner add someone
- m_sender = Address(0x12);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true));
// and check that a non-owner cannot add a new owner
- m_sender = Address(0x50);
+ m_sender = account(0);
+ sendEther(account(2), 10 * eth::ether);
+ m_sender = account(2);
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x20)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x20)) == encodeArgs(false));
// finally check that all the owners are there
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(originalOwner, h256::AlignRight)) == encodeArgs(true));
- BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true));
+ BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs(true));
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true));
}
@@ -548,32 +551,37 @@ BOOST_AUTO_TEST_CASE(initial_owners)
BOOST_AUTO_TEST_CASE(multisig_value_transfer)
{
deployWallet(200);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(2), h256::AlignRight)) == encodeArgs());
+ 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
- h256 opHash("6244b4fa93f73e09db0ae52750095ca0364a76b72bc01723c97011fcb876cc9e");
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x13);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x14);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
+ auto ophash = callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(2), 10 * eth::ether);
+ m_sender = account(2);
+ callContractFunction("confirm(bytes32)", ophash);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(3), 10 * eth::ether);
+ m_sender = account(3);
+ callContractFunction("confirm(bytes32)", ophash);
// now it should go through
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 100);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 100);
}
BOOST_AUTO_TEST_CASE(revoke_addOwner)
{
deployWallet();
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(2), h256::AlignRight)) == encodeArgs());
+ 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());
// add a new owner
@@ -581,16 +589,22 @@ BOOST_AUTO_TEST_CASE(revoke_addOwner)
h256 opHash = sha3(FixedHash<4>(dev::sha3("addOwner(address)")).asBytes() + h256(0x33).asBytes());
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
- m_sender = Address(0x12);
+ m_sender = account(0);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
// revoke one confirmation
m_sender = deployer;
BOOST_REQUIRE(callContractFunction("revoke(bytes32)", opHash) == encodeArgs());
- m_sender = Address(0x13);
+ m_sender = account(0);
+ sendEther(account(2), 10 * eth::ether);
+ m_sender = account(2);
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(false));
- m_sender = Address(0x14);
+ m_sender = account(0);
+ sendEther(account(3), 10 * eth::ether);
+ m_sender = account(3);
BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x33)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x33)) == encodeArgs(true));
}
@@ -598,30 +612,37 @@ BOOST_AUTO_TEST_CASE(revoke_addOwner)
BOOST_AUTO_TEST_CASE(revoke_transaction)
{
deployWallet(200);
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(2), h256::AlignRight)) == encodeArgs());
+ 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());
// create a transaction
Address deployer = m_sender;
- h256 opHash("6244b4fa93f73e09db0ae52750095ca0364a76b72bc01723c97011fcb876cc9e");
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x13);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
+ auto opHash = callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(2), 10 * eth::ether);
+ m_sender = account(2);
+ callContractFunction("confirm(bytes32)", opHash);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
BOOST_REQUIRE(callContractFunction("revoke(bytes32)", opHash) == encodeArgs());
m_sender = deployer;
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x14);
- BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash));
+ callContractFunction("confirm(bytes32)", opHash);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ m_sender = account(0);
+ sendEther(account(3), 10 * eth::ether);
+ m_sender = account(3);
+ callContractFunction("confirm(bytes32)", opHash);
// now it should go through
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 100);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 100);
}
BOOST_AUTO_TEST_CASE(daylimit)
@@ -630,34 +651,38 @@ BOOST_AUTO_TEST_CASE(daylimit)
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(0)));
BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(100)) == encodeArgs());
BOOST_REQUIRE(callContractFunction("m_dailyLimit()") == encodeArgs(u256(100)));
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs());
- BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(1), h256::AlignRight)) == encodeArgs());
+ BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(account(2), h256::AlignRight)) == encodeArgs());
+ 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());
// try to send tx over daylimit
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
- m_sender = Address(0x12);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
+ sendEther(account(1), 10 * eth::ether);
+ m_sender = account(1);
BOOST_REQUIRE(
callContractFunction("execute(address,uint256,bytes)", h256(0x05), 150, 0x60, 0x00) !=
encodeArgs(u256(0))
);
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
// try to send tx under daylimit by stranger
- m_sender = Address(0x77);
+ m_sender = account(0);
+ sendEther(account(4), 10 * eth::ether);
+ m_sender = account(4);
BOOST_REQUIRE(
callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) ==
encodeArgs(u256(0))
);
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 0);
// now send below limit by owner
- m_sender = Address(0x12);
+ m_sender = account(0);
+ sendEther(account(1), 10 * eth::ether);
BOOST_REQUIRE(
callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) ==
encodeArgs(u256(0))
);
- BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 90);
+ BOOST_CHECK_EQUAL(balanceAt(Address(0x05)), 90);
}
BOOST_AUTO_TEST_CASE(daylimit_constructor)
diff --git a/test/libsolidity/CMakeLists.txt b/test/libsolidity/CMakeLists.txt
deleted file mode 100644
index 3ceda13b..00000000
--- a/test/libsolidity/CMakeLists.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-cmake_policy(SET CMP0015 NEW)
-
-aux_source_directory(. SRCS)
-
-add_sources(${SRCS})
diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp
index ebd5d774..fc7a033f 100644
--- a/test/libsolidity/GasMeter.cpp
+++ b/test/libsolidity/GasMeter.cpp
@@ -20,7 +20,7 @@
* Unit tests for the gas estimator.
*/
-#include <test/libsolidity/solidityExecutionFramework.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
#include <libevmasm/GasMeter.h>
#include <libevmasm/KnownState.h>
#include <libevmasm/PathGasMeter.h>
@@ -66,7 +66,11 @@ public:
PathGasMeter meter(*m_compiler.assemblyItems());
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
+ // costs for deployment
gas += bytecodeSize * schedule.createDataGas;
+ // costs for transaction
+ gas += gasForTransaction(m_compiler.object().bytecode, true);
+
BOOST_REQUIRE(!gas.isInfinite);
BOOST_CHECK(gas.value == m_gasUsed);
}
@@ -76,14 +80,16 @@ public:
void testRunTimeGas(string const& _sig, vector<bytes> _argumentVariants)
{
u256 gasUsed = 0;
+ GasMeter::GasConsumption gas;
FixedHash<4> hash(dev::sha3(_sig));
for (bytes const& arguments: _argumentVariants)
{
sendMessage(hash.asBytes() + arguments, false, 0);
gasUsed = max(gasUsed, m_gasUsed);
+ gas = max(gas, gasForTransaction(hash.asBytes() + arguments, false));
}
- GasMeter::GasConsumption gas = GasEstimator::functionalEstimation(
+ gas += GasEstimator::functionalEstimation(
*m_compiler.runtimeAssemblyItems(),
_sig
);
@@ -91,6 +97,15 @@ public:
BOOST_CHECK(gas.value == m_gasUsed);
}
+ static GasMeter::GasConsumption gasForTransaction(bytes const& _data, bool _isCreation)
+ {
+ EVMSchedule schedule;
+ GasMeter::GasConsumption gas = _isCreation ? schedule.txCreateGas : schedule.txGas;
+ for (auto i: _data)
+ gas += i != 0 ? schedule.txDataNonZeroGas : schedule.txDataZeroGas;
+ return gas;
+ }
+
protected:
map<ASTNode const*, eth::GasMeter::GasConsumption> m_gasCosts;
};
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 07bf6759..8dcc878e 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -26,7 +26,7 @@
#include <boost/test/unit_test.hpp>
#include <libdevcore/Hash.h>
#include <libsolidity/interface/Exceptions.h>
-#include <test/libsolidity/solidityExecutionFramework.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
using namespace std;
@@ -1325,10 +1325,10 @@ BOOST_AUTO_TEST_CASE(blockchain)
" blockNumber = block.number;\n"
" }\n"
"}\n";
- m_envInfo.setAuthor(Address(0x123));
- m_envInfo.setNumber(7);
+ BOOST_CHECK(m_rpc.rpcCall("miner_setEtherbase", {"\"0x1212121212121212121212121212121212121212\""}).asBool() == true);
+ m_rpc.test_mineBlocks(5);
compileAndRun(sourceCode, 27);
- BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, 0x123, 7));
+ BOOST_CHECK(callContractFunctionWithValue("someInfo()", 28) == encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7));
}
BOOST_AUTO_TEST_CASE(msg_sig)
@@ -1368,9 +1368,9 @@ BOOST_AUTO_TEST_CASE(now)
" val = now;\n"
" }\n"
"}\n";
- m_envInfo.setTimestamp(9);
+ m_rpc.test_modifyTimestamp(0x776347e2);
compileAndRun(sourceCode);
- BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true, 9));
+ BOOST_CHECK(callContractFunction("someInfo()") == encodeArgs(true, 0x776347e3));
}
BOOST_AUTO_TEST_CASE(type_conversions_cleanup)
@@ -1541,7 +1541,7 @@ BOOST_AUTO_TEST_CASE(send_ether)
compileAndRun(sourceCode, amount + 1);
u160 address(23);
BOOST_CHECK(callContractFunction("a(address,uint256)", address, amount) == encodeArgs(1));
- BOOST_CHECK_EQUAL(m_state.balance(address), amount);
+ BOOST_CHECK_EQUAL(balanceAt(address), amount);
}
BOOST_AUTO_TEST_CASE(log0)
@@ -1553,7 +1553,7 @@ BOOST_AUTO_TEST_CASE(log0)
"}\n";
compileAndRun(sourceCode);
callContractFunction("a()");
- BOOST_CHECK_EQUAL(m_logs.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 0);
@@ -1568,10 +1568,10 @@ BOOST_AUTO_TEST_CASE(log1)
"}\n";
compileAndRun(sourceCode);
callContractFunction("a()");
- BOOST_CHECK_EQUAL(m_logs.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
- BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(u256(2)));
}
@@ -1584,10 +1584,10 @@ BOOST_AUTO_TEST_CASE(log2)
"}\n";
compileAndRun(sourceCode);
callContractFunction("a()");
- BOOST_CHECK_EQUAL(m_logs.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
- BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 2);
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2);
for (unsigned i = 0; i < 2; ++i)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2)));
}
@@ -1601,10 +1601,10 @@ BOOST_AUTO_TEST_CASE(log3)
"}\n";
compileAndRun(sourceCode);
callContractFunction("a()");
- BOOST_CHECK_EQUAL(m_logs.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
- BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 3);
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3);
for (unsigned i = 0; i < 3; ++i)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2)));
}
@@ -1618,10 +1618,10 @@ BOOST_AUTO_TEST_CASE(log4)
"}\n";
compileAndRun(sourceCode);
callContractFunction("a()");
- BOOST_CHECK_EQUAL(m_logs.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
- BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 4);
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 4);
for (unsigned i = 0; i < 4; ++i)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2)));
}
@@ -1634,10 +1634,10 @@ BOOST_AUTO_TEST_CASE(log_in_constructor)
" }\n"
"}\n";
compileAndRun(sourceCode);
- BOOST_CHECK_EQUAL(m_logs.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1)));
- BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 1);
+ BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(u256(2)));
}
@@ -1653,8 +1653,8 @@ BOOST_AUTO_TEST_CASE(suicide)
compileAndRun(sourceCode, amount);
u160 address(23);
BOOST_CHECK(callContractFunction("a(address)", address) == bytes());
- BOOST_CHECK(!m_state.addressHasCode(m_contractAddress));
- BOOST_CHECK_EQUAL(m_state.balance(address), amount);
+ BOOST_CHECK(!addressHasCode(m_contractAddress));
+ BOOST_CHECK_EQUAL(balanceAt(address), amount);
}
BOOST_AUTO_TEST_CASE(selfdestruct)
@@ -1669,8 +1669,8 @@ BOOST_AUTO_TEST_CASE(selfdestruct)
compileAndRun(sourceCode, amount);
u160 address(23);
BOOST_CHECK(callContractFunction("a(address)", address) == bytes());
- BOOST_CHECK(!m_state.addressHasCode(m_contractAddress));
- BOOST_CHECK_EQUAL(m_state.balance(address), amount);
+ BOOST_CHECK(!addressHasCode(m_contractAddress));
+ BOOST_CHECK_EQUAL(balanceAt(address), amount);
}
BOOST_AUTO_TEST_CASE(sha3)
@@ -2462,13 +2462,12 @@ BOOST_AUTO_TEST_CASE(use_std_lib)
contract Icarus is mortal { }
)";
m_addStandardSources = true;
- u256 amount(130);
- u160 address(23);
+ u256 amount(130 * eth::ether);
compileAndRun(sourceCode, amount, "Icarus");
- u256 balanceBefore = m_state.balance(m_sender);
+ u256 balanceBefore = balanceAt(m_sender);
BOOST_CHECK(callContractFunction("kill()") == bytes());
- BOOST_CHECK(!m_state.addressHasCode(m_contractAddress));
- BOOST_CHECK(m_state.balance(m_sender) > balanceBefore);
+ BOOST_CHECK(!addressHasCode(m_contractAddress));
+ BOOST_CHECK(balanceAt(m_sender) > balanceBefore);
}
BOOST_AUTO_TEST_CASE(crazy_elementary_typenames_on_stack)
@@ -2567,7 +2566,7 @@ BOOST_AUTO_TEST_CASE(event)
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,bytes32,uint256)")));
- BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender));
+ BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id));
}
}
@@ -2624,7 +2623,7 @@ BOOST_AUTO_TEST_CASE(event_anonymous_with_topics)
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs("abc"));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 4);
- BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(m_sender));
+ BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(id));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(value));
BOOST_CHECK_EQUAL(m_logs[0].topics[3], h256(2));
@@ -2876,7 +2875,7 @@ BOOST_AUTO_TEST_CASE(generic_call)
u160 const c_receiverAddress = m_contractAddress;
compileAndRun(sourceCode, 50, "sender");
BOOST_REQUIRE(callContractFunction("doSend(address)", c_receiverAddress) == encodeArgs(23));
- BOOST_CHECK_EQUAL(m_state.balance(m_contractAddress), 50 - 2);
+ BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 50 - 2);
}
BOOST_AUTO_TEST_CASE(generic_callcode)
@@ -2904,10 +2903,10 @@ BOOST_AUTO_TEST_CASE(generic_callcode)
BOOST_CHECK(callContractFunction("received()") == encodeArgs(23));
m_contractAddress = c_receiverAddress;
BOOST_CHECK(callContractFunction("received()") == encodeArgs(0));
- BOOST_CHECK(m_state.storage(c_receiverAddress).empty());
- BOOST_CHECK(!m_state.storage(c_senderAddress).empty());
- BOOST_CHECK_EQUAL(m_state.balance(c_receiverAddress), 0);
- BOOST_CHECK_EQUAL(m_state.balance(c_senderAddress), 50);
+ BOOST_CHECK(storageEmpty(c_receiverAddress));
+ BOOST_CHECK(!storageEmpty(c_senderAddress));
+ BOOST_CHECK_EQUAL(balanceAt(c_receiverAddress), 0);
+ BOOST_CHECK_EQUAL(balanceAt(c_senderAddress), 50);
}
BOOST_AUTO_TEST_CASE(generic_delegatecall)
@@ -2943,10 +2942,10 @@ BOOST_AUTO_TEST_CASE(generic_delegatecall)
BOOST_CHECK(callContractFunction("received()") == encodeArgs(u256(0)));
BOOST_CHECK(callContractFunction("sender()") == encodeArgs(u256(0)));
BOOST_CHECK(callContractFunction("value()") == encodeArgs(u256(0)));
- BOOST_CHECK(m_state.storage(c_receiverAddress).empty());
- BOOST_CHECK(!m_state.storage(c_senderAddress).empty());
- BOOST_CHECK_EQUAL(m_state.balance(c_receiverAddress), 0);
- BOOST_CHECK_EQUAL(m_state.balance(c_senderAddress), 50 + 11);
+ BOOST_CHECK(storageEmpty(c_receiverAddress));
+ BOOST_CHECK(!storageEmpty(c_senderAddress));
+ BOOST_CHECK_EQUAL(balanceAt(c_receiverAddress), 0);
+ BOOST_CHECK_EQUAL(balanceAt(c_senderAddress), 50 + 11);
}
BOOST_AUTO_TEST_CASE(library_call_in_homestead)
@@ -3073,9 +3072,9 @@ BOOST_AUTO_TEST_CASE(delete_removes_bytes_data)
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("---", 7) == bytes());
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("del()", 7) == encodeArgs(true));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)
@@ -3089,10 +3088,10 @@ BOOST_AUTO_TEST_CASE(copy_from_calldata_removes_bytes_data)
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
sendMessage(bytes(), false);
BOOST_CHECK(m_output == bytes());
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(copy_removes_bytes_data)
@@ -3107,9 +3106,9 @@ BOOST_AUTO_TEST_CASE(copy_removes_bytes_data)
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("set()", 1, 2, 3, 4, 5) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("reset()") == encodeArgs(true));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(bytes_inside_mappings)
@@ -3125,15 +3124,15 @@ BOOST_AUTO_TEST_CASE(bytes_inside_mappings)
// store a short byte array at 1 and a longer one at 2
BOOST_CHECK(callContractFunction("set(uint256)", 1, 2) == encodeArgs(true));
BOOST_CHECK(callContractFunction("set(uint256)", 2, 2, 3, 4, 5) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
// copy shorter to longer
BOOST_CHECK(callContractFunction("copy(uint256,uint256)", 1, 2) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
// copy empty to both
BOOST_CHECK(callContractFunction("copy(uint256,uint256)", 99, 1) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("copy(uint256,uint256)", 99, 2) == encodeArgs(true));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(bytes_length_member)
@@ -3216,15 +3215,15 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
)";
compileAndRun(sourceCode);
string data = "123456789012345678901234567890123";
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("del()") == encodeArgs(true));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(struct_copy_via_local)
@@ -3496,11 +3495,11 @@ BOOST_AUTO_TEST_CASE(fixed_array_cleanup)
}
)";
compileAndRun(sourceCode);
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("fill()") == bytes());
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("clear()") == bytes());
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
@@ -3517,11 +3516,11 @@ BOOST_AUTO_TEST_CASE(short_fixed_array_cleanup)
}
)";
compileAndRun(sourceCode);
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("fill()") == bytes());
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("clear()") == bytes());
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
@@ -3539,13 +3538,13 @@ BOOST_AUTO_TEST_CASE(dynamic_array_cleanup)
}
)";
compileAndRun(sourceCode);
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("fill()") == bytes());
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("halfClear()") == bytes());
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("fullClear()") == bytes());
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup)
@@ -3565,11 +3564,11 @@ BOOST_AUTO_TEST_CASE(dynamic_multi_array_cleanup)
}
)";
compileAndRun(sourceCode);
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("fill()") == encodeArgs(8));
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("clear()") == bytes());
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn)
@@ -3594,7 +3593,7 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_dyn_dyn)
BOOST_CHECK(callContractFunction("setData1(uint256,uint256,uint256)", 0, 0, 0) == bytes());
BOOST_CHECK(callContractFunction("copyStorageStorage()") == bytes());
BOOST_CHECK(callContractFunction("getData2(uint256)", 0) == encodeArgs(0, 0));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(array_copy_storage_storage_static_static)
@@ -3775,7 +3774,7 @@ BOOST_AUTO_TEST_CASE(array_copy_storage_storage_struct)
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(4, 5));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(array_push)
@@ -3992,9 +3991,9 @@ BOOST_AUTO_TEST_CASE(array_copy_including_mapping)
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(0x02000200));
// storage is not empty because we cannot delete the mappings
- BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(!storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("clear()") == encodeArgs(7));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(pass_dynamic_arguments_to_the_base)
@@ -4204,7 +4203,7 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_delete)
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("test()") == encodeArgs(1));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_first)
@@ -5890,11 +5889,11 @@ BOOST_AUTO_TEST_CASE(short_strings)
compileAndRun(sourceCode, 0, "A");
BOOST_CHECK(callContractFunction("data1()") == encodeDyn(string("123")));
BOOST_CHECK(callContractFunction("lengthChange()") == encodeArgs(u256(0)));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("deleteElements()") == encodeArgs(u256(0)));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
BOOST_CHECK(callContractFunction("copy()") == encodeArgs(u256(0)));
- BOOST_CHECK(m_state.storage(m_contractAddress).empty());
+ BOOST_CHECK(storageEmpty(m_contractAddress));
}
BOOST_AUTO_TEST_CASE(calldata_offset)
@@ -5950,14 +5949,14 @@ BOOST_AUTO_TEST_CASE(reject_ether_sent_to_library)
compileAndRun(sourceCode, 0, "lib");
Address libraryAddress = m_contractAddress;
compileAndRun(sourceCode, 10, "c");
- BOOST_CHECK_EQUAL(m_state.balance(m_contractAddress), 10);
- BOOST_CHECK_EQUAL(m_state.balance(libraryAddress), 0);
+ BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
+ BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0);
BOOST_CHECK(callContractFunction("f(address)", encodeArgs(u160(libraryAddress))) == encodeArgs(false));
- BOOST_CHECK_EQUAL(m_state.balance(m_contractAddress), 10);
- BOOST_CHECK_EQUAL(m_state.balance(libraryAddress), 0);
+ BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
+ BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0);
BOOST_CHECK(callContractFunction("f(address)", encodeArgs(u160(m_contractAddress))) == encodeArgs(true));
- BOOST_CHECK_EQUAL(m_state.balance(m_contractAddress), 10);
- BOOST_CHECK_EQUAL(m_state.balance(libraryAddress), 0);
+ BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 10);
+ BOOST_CHECK_EQUAL(balanceAt(libraryAddress), 0);
}
BOOST_AUTO_TEST_CASE(multi_variable_declaration)
diff --git a/test/libsolidity/SolidityExecutionFramework.cpp b/test/libsolidity/SolidityExecutionFramework.cpp
new file mode 100644
index 00000000..da9cf5f1
--- /dev/null
+++ b/test/libsolidity/SolidityExecutionFramework.cpp
@@ -0,0 +1,147 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum 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.
+
+ cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2016
+ * Framework for executing Solidity contracts and testing them against C++ implementation.
+ */
+
+#include <cstdlib>
+#include <boost/test/framework.hpp>
+#include <test/libsolidity/SolidityExecutionFramework.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+using namespace dev::solidity::test;
+
+string getIPCSocketPath()
+{
+ string ipcPath;
+
+ size_t argc = boost::unit_test::framework::master_test_suite().argc;
+ char** argv = boost::unit_test::framework::master_test_suite().argv;
+ for (size_t i = 0; i < argc; i++)
+ {
+ string arg = argv[i];
+ if (arg == "--ipc" && i + 1 < argc)
+ {
+ ipcPath = argv[i + 1];
+ i++;
+ }
+ }
+ if (ipcPath.empty())
+ if (auto path = getenv("ETH_TEST_IPC"))
+ ipcPath = path;
+ if (ipcPath.empty())
+ BOOST_FAIL("ERROR: ipcPath not set! (use --ipc <path> or the environment variable ETH_TEST_IPC)");
+ return ipcPath;
+}
+
+ExecutionFramework::ExecutionFramework() :
+ m_rpc(RPCSession::instance(getIPCSocketPath())),
+ m_sender(m_rpc.account(0))
+{
+ if (g_logVerbosity != -1)
+ g_logVerbosity = 0;
+
+ m_rpc.test_rewindToBlock(0);
+}
+
+void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value)
+{
+ RPCSession::TransactionData d;
+ d.data = "0x" + toHex(_data);
+ d.from = "0x" + toString(m_sender);
+ d.gas = toHex(m_gas, HexPrefix::Add);
+ d.gasPrice = toHex(m_gasPrice, HexPrefix::Add);
+ d.value = toHex(_value, HexPrefix::Add);
+ if (!_isCreation)
+ {
+ d.to = dev::toString(m_contractAddress);
+ BOOST_REQUIRE(m_rpc.eth_getCode(d.to, "latest").size() > 2);
+ // Use eth_call to get the output
+ m_output = fromHex(m_rpc.eth_call(d, "latest"), WhenError::Throw);
+ }
+
+ string txHash = m_rpc.eth_sendTransaction(d);
+ m_rpc.test_mineBlocks(1);
+ RPCSession::TransactionReceipt receipt(m_rpc.eth_getTransactionReceipt(txHash));
+
+ if (_isCreation)
+ {
+ m_contractAddress = Address(receipt.contractAddress);
+ BOOST_REQUIRE(m_contractAddress);
+ string code = m_rpc.eth_getCode(receipt.contractAddress, "latest");
+ m_output = fromHex(code, WhenError::Throw);
+ }
+
+ m_gasUsed = u256(receipt.gasUsed);
+ m_logs.clear();
+ for (auto const& log: receipt.logEntries)
+ {
+ LogEntry entry;
+ entry.address = Address(log.address);
+ for (auto const& topic: log.topics)
+ entry.topics.push_back(h256(topic));
+ entry.data = fromHex(log.data, WhenError::Throw);
+ m_logs.push_back(entry);
+ }
+}
+
+void ExecutionFramework::sendEther(Address const& _to, u256 const& _value)
+{
+ RPCSession::TransactionData d;
+ d.data = "0x";
+ d.from = "0x" + toString(m_sender);
+ d.gas = toHex(m_gas, HexPrefix::Add);
+ d.gasPrice = toHex(m_gasPrice, HexPrefix::Add);
+ d.value = toHex(_value, HexPrefix::Add);
+ d.to = dev::toString(_to);
+
+ string txHash = m_rpc.eth_sendTransaction(d);
+ m_rpc.test_mineBlocks(1);
+}
+
+size_t ExecutionFramework::currentTimestamp()
+{
+ auto latestBlock = m_rpc.rpcCall("eth_getBlockByNumber", {"\"latest\"", "false"});
+ return size_t(u256(latestBlock.get("timestamp", "invalid").asString()));
+}
+
+Address ExecutionFramework::account(size_t _i)
+{
+ return Address(m_rpc.accountCreateIfNotExists(_i));
+}
+
+bool ExecutionFramework::addressHasCode(Address const& _addr)
+{
+ string code = m_rpc.eth_getCode(toString(_addr), "latest");
+ return !code.empty() && code != "0x";
+}
+
+u256 ExecutionFramework::balanceAt(Address const& _addr)
+{
+ return u256(m_rpc.eth_getBalance(toString(_addr), "latest"));
+}
+
+bool ExecutionFramework::storageEmpty(Address const& _addr)
+{
+ h256 root(m_rpc.eth_getStorageRoot(toString(_addr), "latest"));
+ BOOST_CHECK(root);
+ return root == EmptyTrie;
+}
diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h
index 3fcbfaed..2b589498 100644
--- a/test/libsolidity/solidityExecutionFramework.h
+++ b/test/libsolidity/SolidityExecutionFramework.h
@@ -24,7 +24,9 @@
#include <string>
#include <tuple>
+#include <fstream>
#include "../TestHelper.h"
+#include "../RPCSession.h"
#include <libethcore/ABI.h>
#include <libethcore/SealEngine.h>
#include <libethereum/State.h>
@@ -37,7 +39,6 @@
namespace dev
{
-
namespace solidity
{
namespace test
@@ -45,16 +46,9 @@ namespace test
class ExecutionFramework
{
+
public:
- ExecutionFramework():
- m_state(0)
- {
- eth::NoProof::init();
- m_sealEngine.reset(eth::ChainParams().createSealEngine());
- if (g_logVerbosity != -1)
- g_logVerbosity = 0;
- //m_state.resetCurrent();
- }
+ ExecutionFramework();
bytes const& compileAndRunWithoutCheck(
std::string const& _sourceCode,
@@ -111,7 +105,8 @@ public:
"Computed values do not match.\nSolidity: " +
toHex(solidityResult) +
"\nC++: " +
- toHex(cppResult));
+ toHex(cppResult)
+ );
}
template <class CppFunction, class... Args>
@@ -254,45 +249,26 @@ private:
}
protected:
- void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0)
+ void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0);
+ void sendEther(Address const& _to, u256 const& _value);
+ size_t currentTimestamp();
+
+ /// @returns the (potentially newly created) _ith address.
+ Address account(size_t _i);
+
+ u256 balanceAt(Address const& _addr);
+ bool storageEmpty(Address const& _addr);
+ bool addressHasCode(Address const& _addr);
+
+ RPCSession& m_rpc;
+
+ struct LogEntry
{
- m_state.addBalance(m_sender, _value); // just in case
- eth::Executive executive(m_state, m_envInfo, m_sealEngine.get());
- eth::ExecutionResult res;
- executive.setResultRecipient(res);
- eth::Transaction t =
- _isCreation ?
- eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) :
- eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
- bytes transactionRLP = t.rlp();
- try
- {
- // this will throw since the transaction is invalid, but it should nevertheless store the transaction
- executive.initialize(&transactionRLP);
- executive.execute();
- }
- catch (...) {}
- if (_isCreation)
- {
- BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender));
- m_contractAddress = executive.newAddress();
- BOOST_REQUIRE(m_contractAddress);
- BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
- }
- else
- {
- BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
- BOOST_REQUIRE(!executive.call(m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas));
- }
- BOOST_REQUIRE(executive.go(/* DEBUG eth::Executive::simpleTrace() */));
- m_state.noteSending(m_sender);
- executive.finalize();
- m_gasUsed = res.gasUsed;
- m_output = std::move(res.output);
- m_logs = executive.logs();
- }
+ Address address;
+ std::vector<h256> topics;
+ bytes data;
+ };
- std::unique_ptr<eth::SealEngineFace> m_sealEngine;
size_t m_optimizeRuns = 200;
bool m_optimize = false;
bool m_addStandardSources = false;
@@ -300,11 +276,10 @@ protected:
Address m_sender;
Address m_contractAddress;
eth::EnvInfo m_envInfo;
- eth::State m_state;
u256 const m_gasPrice = 100 * eth::szabo;
u256 const m_gas = 100000000;
bytes m_output;
- eth::LogEntries m_logs;
+ std::vector<LogEntry> m_logs;
u256 m_gasUsed;
};
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 697b3fa9..7e81bd7e 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -3750,6 +3750,79 @@ BOOST_AUTO_TEST_CASE(one_divided_by_three_integer_conversion)
BOOST_CHECK(!success(text));
}
+BOOST_AUTO_TEST_CASE(unused_return_value)
+{
+ char const* text = R"(
+ contract test {
+ function g() returns (uint) {}
+ function f() {
+ g();
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
+BOOST_AUTO_TEST_CASE(unused_return_value_send)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ address(0x12).send(1);
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
+}
+
+BOOST_AUTO_TEST_CASE(unused_return_value_call)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ address(0x12).call("abc");
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
+}
+
+BOOST_AUTO_TEST_CASE(unused_return_value_call_value)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ address(0x12).call.value(2)("abc");
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
+}
+
+BOOST_AUTO_TEST_CASE(unused_return_value_callcode)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ address(0x12).callcode("abc");
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
+}
+
+BOOST_AUTO_TEST_CASE(unused_return_value_delegatecall)
+{
+ char const* text = R"(
+ contract test {
+ function f() {
+ address(0x12).delegatecall("abc");
+ }
+ }
+ )";
+ BOOST_CHECK(expectError(text, true) == Error::Type::Warning);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp
index d48c7648..ad573823 100644
--- a/test/libsolidity/SolidityOptimizer.cpp
+++ b/test/libsolidity/SolidityOptimizer.cpp
@@ -25,7 +25,7 @@
#include <memory>
#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>
-#include <test/libsolidity/solidityExecutionFramework.h>
+#include <test/libsolidity/SolidityExecutionFramework.h>
#include <libevmasm/CommonSubexpressionEliminator.h>
#include <libevmasm/ControlFlowGraph.h>
#include <libevmasm/Assembly.h>