diff options
49 files changed, 533 insertions, 177 deletions
diff --git a/.travis.yml b/.travis.yml index da9bd2f9..1f35a509 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,10 +84,11 @@ matrix: # OS X Mavericks (10.9) # https://en.wikipedia.org/wiki/OS_X_Mavericks # - - os: osx - osx_image: beta-xcode6.2 - env: - - ZIP_SUFFIX=osx-mavericks +# Disabled because of problems on travis. +# - os: osx +# osx_image: beta-xcode6.2 +# env: +# - ZIP_SUFFIX=osx-mavericks # OS X Yosemite (10.10) # https://en.wikipedia.org/wiki/OS_X_Yosemite @@ -186,7 +187,9 @@ deploy: script: test $TRAVIS_EMSCRIPTEN != On || scripts/release_emscripten.sh skip_cleanup: true on: - branch: develop + branch: + - develop + - release # This is the deploy target for the native build (Linux and macOS) # which generates ZIPs per commit. We are in agreement that diff --git a/CMakeLists.txt b/CMakeLists.txt index f190a507..62440265 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.4.2") +set(PROJECT_VERSION "0.4.3") project(solidity VERSION ${PROJECT_VERSION}) # Let's find our dependencies diff --git a/Changelog.md b/Changelog.md index 1ae18658..bc79b88a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,29 @@ +### 0.4.3 (unreleased) + +Features: + + * Inline assembly: support both `sucide` and `selfdestruct` opcodes + (note: `suicide` is deprecated) + * Include `keccak256()` as an alias to `sha3()` + +Bugfixes: + * Disallow unknown options in `solc` + * Inline assembly: support the `address` opcode + * Inline assembly: fix parsing of assignment after a label. + +### 0.4.2 (2016-09-17) + +Bugfixes: + + * Code Generator: Fix library functions being called from payable functions. + * Type Checker: Fixed a crash about invalid array types. + * Code Generator: Fixed a call gas bug that became visible after + version 0.4.0 for calls where the output is larger than the input. + +### 0.4.1 (2016-09-09) + + * Build System: Fixes to allow library compilation. + ### 0.4.0 (2016-09-08) This release deliberately breaks backwards compatibility mostly to diff --git a/cmake/scripts/buildinfo.cmake b/cmake/scripts/buildinfo.cmake index f0e39906..8e1615f6 100644 --- a/cmake/scripts/buildinfo.cmake +++ b/cmake/scripts/buildinfo.cmake @@ -34,7 +34,7 @@ if (EXISTS ${ETH_SOURCE_DIR}/commit_hash.txt) string(STRIP ${SOL_COMMIT_HASH} SOL_COMMIT_HASH) else() execute_process( - COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} rev-parse HEAD + COMMAND git --git-dir=${ETH_SOURCE_DIR}/.git --work-tree=${ETH_SOURCE_DIR} rev-parse --short=8 HEAD OUTPUT_VARIABLE SOL_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) execute_process( @@ -48,14 +48,17 @@ if (SOL_COMMIT_HASH) string(SUBSTRING ${SOL_COMMIT_HASH} 0 8 SOL_COMMIT_HASH) endif() -if (SOL_COMMIT_HASH AND SOL_LOCAL_CHANGES) - set(SOL_COMMIT_HASH "${SOL_COMMIT_HASH}.mod") -endif() - if (NOT SOL_COMMIT_HASH) message(FATAL_ERROR "Unable to determine commit hash. Either compile from within git repository or " "supply a file called commit_hash.txt") endif() +if (NOT SOL_COMMIT_HASH MATCHES [a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]) + message(FATAL_ERROR "Malformed commit hash \"${SOL_COMMIT_HASH}\". It has to consist of exactly 8 hex digits.") +endif() + +if (SOL_COMMIT_HASH AND SOL_LOCAL_CHANGES) + set(SOL_COMMIT_HASH "${SOL_COMMIT_HASH}.mod") +endif() set(SOL_VERSION_BUILDINFO "commit.${SOL_COMMIT_HASH}.${ETH_BUILD_PLATFORM}") diff --git a/docs/conf.py b/docs/conf.py index d0e26362..4d22c9bd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,9 +56,9 @@ copyright = '2016, Ethereum' # built documents. # # The short X.Y version. -version = '0.2.0' +version = '0.4.3' # The full version, including alpha/beta/rc tags. -release = '0.2.0' +release = '0.4.3-develop' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/contracts.rst b/docs/contracts.rst index ef29a686..986d05b3 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -136,7 +136,7 @@ This means that cyclic creation dependencies are impossible. ) returns (bool ok) { // Check some arbitrary condition. address tokenAddress = msg.sender; - return (sha3(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); + return (keccak256(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); } } @@ -544,7 +544,7 @@ to be searched for: It is possible to filter for specific values of indexed arguments in the user interface. If arrays (including ``string`` and ``bytes``) are used as indexed arguments, the -sha3-hash of it is stored as topic instead. +Keccak-256 hash of it is stored as topic instead. The hash of the signature of the event is one of the topics except if you declared the event with ``anonymous`` specifier. This means that it is @@ -622,7 +622,7 @@ as topics. The event call above can be performed in the same way as ); where the long hexadecimal number is equal to -``sha3("Deposit(address,hash256,uint256)")``, the signature of the event. +``keccak256("Deposit(address,hash256,uint256)")``, the signature of the event. Additional Resources for Understanding Events ============================================== diff --git a/docs/contributing.rst b/docs/contributing.rst index a316abd6..111fb932 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -15,7 +15,9 @@ In particular, we need help in the following areas: <http://ethereum.stackexchange.com/>`_ and the `Solidity Gitter <https://gitter.im/ethereum/solidity>`_ * Fixing and responding to `Solidity's GitHub issues - <https://github.com/ethereum/solidity/issues>`_ + <https://github.com/ethereum/solidity/issues>`_, especially those tagged as + `up-for-grabs <https://github.com/ethereum/solidity/issues?q=is%3Aopen+is%3Aissue+label%3Aup-for-grabs>`_ which are + meant as introductory issues for external contributors. How to Report Issues ==================== diff --git a/docs/control-structures.rst b/docs/control-structures.rst index db24d5c3..6cbbcdf8 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -322,14 +322,16 @@ In the following example, we show how ``throw`` can be used to easily revert an } } -Currently, there are six situations, where exceptions happen automatically in Solidity: - -1. If you access an array beyond its length (i.e. ``x[i]`` where ``i >= x.length``). -2. If a function called via a message call does not finish properly (i.e. it runs out of gas or throws an exception itself). -3. If a non-existent function on a library is called or Ether is sent to a library. -4. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``). -5. If you perform an external function call targeting a contract that contains no code. -6. If a contract-creation call using the ``new`` keyword fails. +Currently, there are situations, where exceptions happen automatically in Solidity: + +1. If you access an array at a too large or negative index (i.e. ``x[i]`` where ``i >= x.length`` or ``i < 0``). +2. If you access a fixed-length ``bytesN`` at a too large or negative index. +3. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall`` or ``callcode`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``. +4. If you create a contract using the ``new`` keyword but the contract creation does not finish properly (see above for the definition of "not finish properly"). +5. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``). +6. If you perform an external function call targeting a contract that contains no code. +7. If your contract receives Ether via a public function without ``payable`` modifier (including the constructor and the fallback function). +8. If your contract receives Ether via a public accessor function. Internally, Solidity performs an "invalid jump" when an exception is thrown and thus causes the EVM to revert all changes made to the state. The reason for this is that there is no safe way to continue execution, because an expected effect did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction (or at least call) without effect. diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index ad27e528..97eada79 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -6,6 +6,15 @@ Installing Solidity ################### +Versioning +========== + +Solidity versions follow `semantic versioning <https://semver.org>` and in addition to +releases, **nightly development builds** are also made available. The nightly builds +are not guaranteed to be working and despite best efforts they might contain undocumented +and/or broken changes. We recommend to use the latest release. Package installers below +will use the latest release. + Browser-Solidity ================ @@ -186,3 +195,21 @@ Alternatively, you can build for Windows on the command-line, like so: .. code:: bash cmake --build . --config RelWithDebInfo + +Important information about versioning +====================================== + +After a release is made, the patch version level is bumped, because we assume that only +patch level changes follow. When changes are merged, the version should be bumped according +to semver and the severity of the change. Finally, a release is always made with the version +of the current nightly build, but without the ``prerelease`` specifier. + +Example: + +0. the 0.4.0 release is made +1. nightly build has a version of 0.4.1 from now on +2. non-breaking changes are introduced - no change in version +3. a breaking change is introduced - version is bumped to 0.5.0 +4. the 0.5.0 release is made + +This behaviour works well with the version pragma. diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 7d4cedb6..d32186ca 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -34,17 +34,17 @@ Statically-sized variables (everything except mapping and dynamically-sized arra The elements of structs and arrays are stored after each other, just as if they were given explicitly. -Due to their unpredictable size, mapping and dynamically-sized array types use a ``sha3`` +Due to their unpredictable size, mapping and dynamically-sized array types use a Keccak-256 hash computation to find the starting position of the value or the array data. These starting positions are always full stack slots. The mapping or the dynamic array itself occupies an (unfilled) slot in storage at some position ``p`` according to the above rule (or by recursively applying this rule for mappings to mappings or arrays of arrays). For a dynamic array, this slot stores the number of elements in the array (byte arrays and strings are an exception here, see below). For a mapping, the slot is unused (but it is needed so that two equal mappings after each other will use a different hash distribution). -Array data is located at ``sha3(p)`` and the value corresponding to a mapping key -``k`` is located at ``sha3(k . p)`` where ``.`` is concatenation. If the value is again a -non-elementary type, the positions are found by adding an offset of ``sha3(k . p)``. +Array data is located at ``keccak256(p)`` and the value corresponding to a mapping key +``k`` is located at ``keccak256(k . p)`` where ``.`` is concatenation. If the value is again a +non-elementary type, the positions are found by adding an offset of ``keccak256(k . p)``. -``bytes`` and ``string`` store their data in the same slot where also the length is stored if they are short. In particular: If the data is at most ``31`` bytes long, it is stored in the higher-order bytes (left aligned) and the lowest-order byte stores ``length * 2``. If it is longer, the main slot stores ``length * 2 + 1`` and the data is stored as usual in ``sha3(slot)``. +``bytes`` and ``string`` store their data in the same slot where also the length is stored if they are short. In particular: If the data is at most ``31`` bytes long, it is stored in the higher-order bytes (left aligned) and the lowest-order byte stores ``length * 2``. If it is longer, the main slot stores ``length * 2 + 1`` and the data is stored as usual in ``keccak256(slot)``. So for the following contract snippet:: @@ -54,7 +54,7 @@ So for the following contract snippet:: mapping(uint => mapping(uint => s)) data; } -The position of ``data[4][9].b`` is at ``sha3(uint256(9) . sha3(uint256(4) . uint256(1))) + 1``. +The position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1``. ***************** Esoteric Features @@ -281,7 +281,7 @@ The following is the order of precedence for operators, listed in order of evalu | *16* | Comma operator | ``,`` | +------------+-------------------------------------+--------------------------------------------+ -.. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, sha3, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send +.. index:: block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send Global Variables ================ @@ -299,7 +299,8 @@ Global Variables - ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``) - ``tx.gasprice`` (``uint``): gas price of the transaction - ``tx.origin`` (``address``): sender of the transaction (full call chain) -- ``sha3(...) returns (bytes32)``: compute the Ethereum-SHA-3 (KECCAK-256) hash of the (tightly packed) arguments +- ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments +- ``sha3(...) returns (bytes32)``: an alias to `keccak256()` - ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments - ``ripemd160(...) returns (bytes20)``: compute the RIPEMD-160 hash of the (tightly packed) arguments - ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error @@ -338,3 +339,16 @@ Modifiers - ``anonymous`` for events: Does not store event signature as topic. - ``indexed`` for event parameters: Stores the parameter as topic. - ``payable`` for functions: Allows them to receive Ether together with a call. + +Reserved Keywords +================= + +These keywords are reserved in Solidity. They might become part of the syntax in the future: + +``abstract``, ``after``, ``case``, ``catch``, ``final``, ``in``, ``inline``, ``interface``, ``let``, ``match``, +``of``, ``pure``, ``relocatable``, ``static``, ``switch``, ``try``, ``type``, ``typeof``, ``view``. + +Language Grammar +================ + +The entire language grammar is `available here <https://github.com/ethereum/solidity/blob/release/libsolidity/grammar.txt>`_. diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index a2f4ec4c..77e1bf08 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -123,7 +123,7 @@ Sending and Receiving Ether ``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. + into the sending contract or other state changes you might not have thought of. So it allows for great flexibility for honest users but also for malicious actors. - If you want to send Ether using ``address.send``, there are certain details to be aware of: @@ -207,7 +207,7 @@ Minor Details You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument of ``0xff000001`` and with ``0x00000001``. Both are fed to the contract and both will look like the number ``1`` as far as ``x`` is concerned, but ``msg.data`` will - be different, so if you use ``sha3(msg.data)`` for anything, you will get different results. + be different, so if you use ``keccak256(msg.data)`` for anything, you will get different results. *************** Recommendations diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 9d3dd6f6..2e53b78c 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -415,7 +415,7 @@ high or low invalid bids. revealEnd = biddingEnd + _revealTime; } - /// Place a blinded bid with `_blindedBid` = sha3(value, + /// Place a blinded bid with `_blindedBid` = keccak256(value, /// fake, secret). /// The sent ether is only refunded if the bid is correctly /// revealed in the revealing phase. The bid is valid if the @@ -459,7 +459,7 @@ high or low invalid bids. var bid = bids[msg.sender][i]; var (value, fake, secret) = (_values[i], _fake[i], _secret[i]); - if (bid.blindedBid != sha3(value, fake, secret)) { + if (bid.blindedBid != keccak256(value, fake, secret)) { // Bid was not actually revealed. // Do not refund deposit. continue; diff --git a/docs/types.rst b/docs/types.rst index 9d7ebec9..5fb512d5 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -106,7 +106,7 @@ the function ``call`` is provided which takes an arbitrary number of arguments o address nameReg = 0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2; nameReg.call("register", "MyName"); - nameReg.call(bytes4(sha3("fun(uint256)")), a); + nameReg.call(bytes4(keccak256("fun(uint256)")), a); ``call`` returns a boolean indicating whether the invoked function terminated (``true``) or caused an EVM exception (``false``). It is not possible to access the actual data returned (for this we would need to know the encoding and size in advance). @@ -186,7 +186,7 @@ the type ``ufixed0x256`` because ``1/3`` is not finitely representable in binary approximated. Any operator that can be applied to integers can also be applied to literal expressions as -long as the operators are integers. If any of the two is fractional, bit operations are disallowed +long as the operands are integers. If any of the two is fractional, bit operations are disallowed and exponentiation is disallowed if the exponent is fractional (because that might result in a non-rational number). @@ -610,7 +610,7 @@ can actually be any type, including mappings. Mappings can be seen as hashtables which are virtually initialized such that every possible key exists and is mapped to a value whose byte-representation is all zeros: a type's :ref:`default value <default-value>`. The similarity ends here, though: The key data is not actually stored -in a mapping, only its ``sha3`` hash used to look up the value. +in a mapping, only its ``keccak256`` hash used to look up the value. Because of this, mappings do not have a length or a concept of a key or value being "set". diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 9ee334cf..3499bc71 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -79,7 +79,7 @@ Block and Transaction Properties You can only access the hashes of the most recent 256 blocks, all other values will be zero. -.. index:: sha3, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send +.. index:: keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send Mathematical and Cryptographic Functions ---------------------------------------- @@ -88,8 +88,10 @@ Mathematical and Cryptographic Functions compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``. ``mulmod(uint x, uint y, uint k) returns (uint)``: compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``. +``keccak256(...) returns (bytes32)``: + compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments ``sha3(...) returns (bytes32)``: - compute the Ethereum-SHA-3 (KECCAK-256) hash of the (tightly packed) arguments + alias to `keccak256()` ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments ``ripemd160(...) returns (bytes20)``: @@ -100,18 +102,18 @@ Mathematical and Cryptographic Functions In the above, "tightly packed" means that the arguments are concatenated without padding. This means that the following are all identical:: - sha3("ab", "c") - sha3("abc") - sha3(0x616263) - sha3(6382179) - sha3(97, 98, 99) + keccak256("ab", "c") + keccak256("abc") + keccak256(0x616263) + keccak256(6382179) + keccak256(97, 98, 99) -If padding is needed, explicit type conversions can be used: ``sha3("\x00\x12")`` is the -same as ``sha3(uint16(0x12))``. +If padding is needed, explicit type conversions can be used: ``keccak256("\x00\x12")`` is the +same as ``keccak256(uint16(0x12))``. Note that constants will be packed using the minimum number of bytes required to store them. -This means that, for example, ``sha3(0) == sha3(uint8(0))`` and -``sha3(0x12345678) == sha3(uint32(0x12345678))``. +This means that, for example, ``keccak256(0) == keccak256(uint8(0))`` and +``keccak256(0x12345678) == keccak256(uint32(0x12345678))``. It might be that you run into Out-of-Gas for ``sha256``, ``ripemd160`` or ``ecrecover`` on a *private blockchain*. The reason for this is that those are implemented as so-called precompiled contracts and these contracts only really exist after they received the first message (although their contract code is hardcoded). Messages to non-existing contracts are more expensive and thus the execution runs into an Out-of-Gas error. A workaround for this problem is to first send e.g. 1 Wei to each of the contracts before you use them in your actual contracts. This is not an issue on the official or test net. diff --git a/libdevcore/ABI.h b/libdevcore/ABI.h index 5b7d160d..423cfda8 100644 --- a/libdevcore/ABI.h +++ b/libdevcore/ABI.h @@ -63,7 +63,7 @@ template <class T, class ... U> bytes abiInAux(T const& _t, U const& ... _u) template <class ... T> bytes abiIn(std::string _id, T const& ... _t) { - return sha3(_id).ref().cropped(0, 4).toBytes() + abiInAux(_t ...); + return keccak256(_id).ref().cropped(0, 4).toBytes() + abiInAux(_t ...); } template <class T> struct ABIDeserialiser {}; diff --git a/libdevcore/Assertions.h b/libdevcore/Assertions.h index 7b4a4a76..05e0b0e5 100644 --- a/libdevcore/Assertions.h +++ b/libdevcore/Assertions.h @@ -73,7 +73,7 @@ inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char con /// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); /// Do NOT supply an exception object as the second parameter. #define assertThrow(_condition, _ExceptionType, _description) \ - ::dev::assertThrowAux<_ExceptionType>(_condition, _description, __LINE__, __FILE__, ETH_FUNC) + ::dev::assertThrowAux<_ExceptionType>(!!(_condition), _description, __LINE__, __FILE__, ETH_FUNC) using errinfo_comment = boost::error_info<struct tag_comment, std::string>; @@ -96,16 +96,4 @@ inline void assertThrowAux( ); } -template <class _ExceptionType> -inline void assertThrowAux( - void const* _pointer, - ::std::string const& _errorDescription, - unsigned _line, - char const* _file, - char const* _function -) -{ - assertThrowAux<_ExceptionType>(_pointer != nullptr, _errorDescription, _line, _file, _function); -} - } diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp index 584ef07e..d4536a34 100644 --- a/libdevcore/SHA3.cpp +++ b/libdevcore/SHA3.cpp @@ -49,12 +49,19 @@ namespace keccak #define decsha3(bits) \ int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); +#define deckeccak(bits) \ + int keccak##bits(uint8_t*, size_t, const uint8_t*, size_t); + decshake(128) decshake(256) decsha3(224) decsha3(256) decsha3(384) decsha3(512) +deckeccak(224) +deckeccak(256) +deckeccak(384) +deckeccak(512) /******** The Keccak-f[1600] permutation ********/ @@ -192,6 +199,14 @@ static inline int hash(uint8_t* out, size_t outlen, if (outlen > (bits/8)) { \ return -1; \ } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \ + } +#define defkeccak(bits) \ + int keccak##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ } @@ -205,17 +220,20 @@ defsha3(256) defsha3(384) defsha3(512) -} +/*** KECCAK FOFs ***/ +defkeccak(224) +defkeccak(256) +defkeccak(384) +defkeccak(512) -unsigned g_sha3Counter = 0; +} -bool sha3(bytesConstRef _input, bytesRef o_output) +bool keccak256(bytesConstRef _input, bytesRef o_output) { // FIXME: What with unaligned memory? if (o_output.size() != 32) return false; - ++g_sha3Counter; - keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size()); + keccak::keccak256(o_output.data(), 32, _input.data(), _input.size()); // keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size()); return true; } diff --git a/libdevcore/SHA3.h b/libdevcore/SHA3.h index 5393952f..eedcc420 100644 --- a/libdevcore/SHA3.h +++ b/libdevcore/SHA3.h @@ -34,26 +34,24 @@ namespace dev /// Calculate SHA3-256 hash of the given input and load it into the given output. /// @returns false if o_output.size() != 32. -bool sha3(bytesConstRef _input, bytesRef o_output); +bool keccak256(bytesConstRef _input, bytesRef o_output); /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; } +inline h256 keccak256(bytesConstRef _input) { h256 ret; keccak256(_input, ret.ref()); return ret; } /// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash. -inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); } +inline h256 keccak256(bytes const& _input) { return keccak256(bytesConstRef(&_input)); } /// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash. -inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } +inline h256 keccak256(std::string const& _input) { return keccak256(bytesConstRef(_input)); } /// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash. -template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); } +template<unsigned N> inline h256 keccak256(FixedHash<N> const& _input) { return keccak256(_input.ref()); } /// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data. -inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); } +inline std::string keccak256(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? keccak256(fromHex(_input)) : keccak256(bytesConstRef(&_input))).asBytes()); } /// Calculate SHA3-256 MAC -inline void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { sha3(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); } - -extern unsigned g_sha3Counter; +inline void keccak256mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { keccak256(_secret.toBytes() + _plain.toBytes()).ref().populate(_output); } } diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index c7822819..450ee6ce 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -296,7 +296,7 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) AssemblyItem Assembly::newPushLibraryAddress(string const& _identifier) { - h256 h(dev::sha3(_identifier)); + h256 h(dev::keccak256(_identifier)); m_libraries[h] = _identifier; return AssemblyItem(PushLibraryAddress, h); } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index af28e220..dae1e1da 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -45,11 +45,11 @@ public: AssemblyItem newTag() { return AssemblyItem(Tag, m_usedTags++); } AssemblyItem newPushTag() { return AssemblyItem(PushTag, m_usedTags++); } - AssemblyItem newData(bytes const& _data) { h256 h(sha3(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } + AssemblyItem newData(bytes const& _data) { h256 h(dev::keccak256(asString(_data))); m_data[h] = _data; return AssemblyItem(PushData, h); } AssemblyItem newSub(Assembly const& _sub) { m_subs.push_back(_sub); return AssemblyItem(PushSub, m_subs.size() - 1); } Assembly const& sub(size_t _sub) const { return m_subs.at(_sub); } Assembly& sub(size_t _sub) { return m_subs.at(_sub); } - AssemblyItem newPushString(std::string const& _data) { h256 h(sha3(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); } + AssemblyItem newPushString(std::string const& _data) { h256 h(dev::keccak256(_data)); m_strings[h] = _data; return AssemblyItem(PushString, h); } AssemblyItem newPushSubSize(u256 const& _subId) { return AssemblyItem(PushSubSize, _subId); } AssemblyItem newPushLibraryAddress(std::string const& _identifier); diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index dd269ff4..0b6e0ac5 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -378,7 +378,7 @@ KnownState::Id KnownState::applySha3( for (Id a: arguments) data += toBigEndian(*m_expressionClasses->knownConstant(a)); data.resize(size_t(*l)); - v = m_expressionClasses->find(AssemblyItem(u256(sha3(data)), _location)); + v = m_expressionClasses->find(AssemblyItem(u256(dev::keccak256(data)), _location)); } else v = m_expressionClasses->find(sha3Item, {_start, _length}, true, m_sequenceNumber); diff --git a/liblll/CompilerState.cpp b/liblll/CompilerState.cpp index 63351bc4..1d83192c 100644 --- a/liblll/CompilerState.cpp +++ b/liblll/CompilerState.cpp @@ -45,8 +45,6 @@ CodeFragment const& CompilerState::getDef(std::string const& _s) void CompilerState::populateStandard() { static const string s = "{" - "(def 'gav 0x51ba59315b3a95761d0863b05ccc7a7f54703d99)" - "(def 'config 0x661005d2720d855f1d9976f88bb10c1a3398c77f)" "(def 'allgas (- (gas) 21))" "(def 'send (to value) (call allgas to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" @@ -60,18 +58,12 @@ void CompilerState::populateStandard() "(def 'sha3 (val) { [0]:val (sha3 0 32) })" "(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })" "(def 'sha3trip (a b c) { [0]:a [32]:b [64]:c (sha3 0 96) })" + "(def 'keccak256 (loc len) (sha3 loc len))" "(def 'return (val) { [0]:val (return 0 32) })" "(def 'returnlll (code) (return 0 (lll code 0)) )" "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" "(def 'permcount 0)" "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" - "(def 'namereg (msg config 0))" - "(def 'coinreg (msg config 1))" - "(def 'gavcoin (msg config 2))" - "(def 'sendgavcoin (to value) { [32]'send [64]:to [96]:value (call allgas gavcoin 0 32 96 0 0) })" - "(def 'regname (name) { [32]'register [64]name (call allgas namereg 0 32 64 0 0) })" - "(def 'regcoin (name) { [32]name (call allgas coinreg 0 32 32 0 0) })" - "(def 'regcoin (name denom) { [32]name [64]denom (call allgas coinreg 0 32 64 0 0) })" "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })" "(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))" "(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))" diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index a7ffcfad..d075949e 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -48,6 +48,8 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared< make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Location::MulMod)), make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)), + make_shared<MagicVariableDeclaration>("keccak256", + make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Location::SHA3, true)), make_shared<MagicVariableDeclaration>("log0", make_shared<FunctionType>(strings{"bytes32"}, strings{}, FunctionType::Location::Log0)), make_shared<MagicVariableDeclaration>("log1", diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index a95b4879..dc8c1806 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -67,7 +67,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma) { solAssert(!_pragma.tokens().empty(), ""); solAssert(_pragma.tokens().size() == _pragma.literals().size(), ""); - if (_pragma.tokens()[0] != Token::Identifier && _pragma.literals()[0] != "solidity") + if (_pragma.tokens()[0] != Token::Identifier || _pragma.literals()[0] != "solidity") syntaxError(_pragma.location(), "Unknown pragma \"" + _pragma.literals()[0] + "\""); else { diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index d9c54f75..ae7c13c8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1438,7 +1438,7 @@ bool TypeChecker::visit(IndexAccess const& _access) length->literalValue(nullptr) )); else - typeError(index->location(), "Integer constant expected."); + fatalTypeError(index->location(), "Integer constant expected."); } break; } diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 294daa13..cca19a4e 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -151,7 +151,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter if (signaturesSeen.count(functionSignature) == 0) { signaturesSeen.insert(functionSignature); - FixedHash<4> hash(dev::sha3(functionSignature)); + FixedHash<4> hash(dev::keccak256(functionSignature)); m_interfaceFunctionList->push_back(make_pair(hash, fun)); } } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 4b5f12ce..6d1af534 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2033,7 +2033,7 @@ string FunctionType::externalSignature() const u256 FunctionType::externalIdentifier() const { - return FixedHash<4>::Arith(FixedHash<4>(dev::sha3(externalSignature()))); + return FixedHash<4>::Arith(FixedHash<4>(dev::keccak256(externalSignature()))); } TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 33571bc0..18b42fce 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -263,7 +263,9 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac CompilerContext::LocationSetter locationSetter(m_context, functionType->declaration()); m_context << callDataUnpackerEntryPoints.at(it.first); - if (!functionType->isPayable()) + // We have to allow this for libraries, because value of the previous + // call is still visible in the delegatecall. + if (!functionType->isPayable() && !_contract.isLibrary()) { // Throw if function is not payable but call contained ether. m_context << Instruction::CALLVALUE; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 96ca4296..3d05edd3 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -670,7 +670,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } if (!event.isAnonymous()) { - m_context << u256(h256::Arith(dev::sha3(function.externalSignature()))); + m_context << u256(h256::Arith(dev::keccak256(function.externalSignature()))); ++numIndexed; } solAssert(numIndexed <= 4, "Too many indexed arguments."); @@ -1476,6 +1476,18 @@ void ExpressionCompiler::appendExternalFunctionCall( utils().storeFreeMemoryPointer(); } + // Touch the end of the output area so that we do not pay for memory resize during the call + // (which we would have to subtract from the gas left) + // We could also just use MLOAD; POP right before the gas calculation, but the optimizer + // would remove that, so we use MSTORE here. + if (!_functionType.gasSet() && retSize > 0) + { + m_context << u256(0); + utils().fetchFreeMemoryPointer(); + // This touches too much, but that way we save some rounding arithmetics + m_context << u256(retSize) << Instruction::ADD << Instruction::MSTORE; + } + // Copy function identifier to memory. utils().fetchFreeMemoryPointer(); if (!_functionType.isBareCall() || manualFunctionId) @@ -1551,10 +1563,7 @@ void ExpressionCompiler::appendExternalFunctionCall( gasNeededByCaller += eth::GasCosts::callValueTransferGas; if (!isCallCode && !isDelegateCall && !existenceChecked) gasNeededByCaller += eth::GasCosts::callNewAccountGas; // we never know - m_context << - gasNeededByCaller << - Instruction::GAS << - Instruction::SUB; + m_context << gasNeededByCaller << Instruction::GAS << Instruction::SUB; } if (isDelegateCall) m_context << Instruction::DELEGATECALL; diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index b441b150..813fa3ab 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -36,6 +36,10 @@ bool Why3Translator::process(SourceUnit const& _source) appendPreface(); _source.accept(*this); } + catch (NoFormalType&) + { + solAssert(false, "There is a call to toFormalType() that does not catch NoFormalType exceptions."); + } catch (FatalError& /*_e*/) { solAssert(m_errorOccured, ""); @@ -77,14 +81,30 @@ string Why3Translator::toFormalType(Type const& _type) const return "uint256"; } else if (auto type = dynamic_cast<ArrayType const*>(&_type)) + { if (!type->isByteArray() && type->isDynamicallySized() && type->dataStoredIn(DataLocation::Memory)) { + // Not catching NoFormalType exception. Let the caller deal with it. string base = toFormalType(*type->baseType()); - if (!base.empty()) - return "array " + base; + return "array " + base; } + } + else if (auto mappingType = dynamic_cast<MappingType const*>(&_type)) + { + solAssert(mappingType->keyType(), "A mappingType misses a keyType."); + if (dynamic_cast<IntegerType const*>(&*mappingType->keyType())) + { + //@TODO Use the information from the key type and specify the length of the array as an invariant. + // Also the constructor need to specify the length of the array. + solAssert(mappingType->valueType(), "A mappingType misses a valueType."); + // Not catching NoFormalType exception. Let the caller deal with it. + string valueTypeFormal = toFormalType(*mappingType->valueType()); + return "array " + valueTypeFormal; + } + } - return ""; + BOOST_THROW_EXCEPTION(NoFormalType() + << errinfo_noFormalTypeFrom(_type.toString(true))); } void Why3Translator::addLine(string const& _line) @@ -142,9 +162,17 @@ bool Why3Translator::visit(ContractDefinition const& _contract) m_currentContract.stateVariables = _contract.stateVariables(); for (VariableDeclaration const* variable: m_currentContract.stateVariables) { - string varType = toFormalType(*variable->annotation().type); - if (varType.empty()) - fatalError(*variable, "Type not supported for state variable."); + string varType; + try + { + varType = toFormalType(*variable->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + string typeName = typeNamePtr ? " \"" + *typeNamePtr + "\"" : ""; + fatalError(*variable, "Type" + typeName + " not supported for state variable."); + } addLine("mutable _" + variable->name() + ": " + varType); } unindent(); @@ -218,9 +246,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function) add(" (this: account)"); for (auto const& param: _function.parameters()) { - string paramType = toFormalType(*param->annotation().type); - if (paramType.empty()) - error(*param, "Parameter type not supported."); + string paramType; + try + { + paramType = toFormalType(*param->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*param, "Parameter type \"" + (typeName ? *typeName : "") + "\" not supported."); + } if (param->name().empty()) error(*param, "Anonymous function parameters not supported."); add(" (arg_" + param->name() + ": " + paramType + ")"); @@ -232,9 +267,16 @@ bool Why3Translator::visit(FunctionDefinition const& _function) string retString = "("; for (auto const& retParam: _function.returnParameters()) { - string paramType = toFormalType(*retParam->annotation().type); - if (paramType.empty()) - error(*retParam, "Parameter type not supported."); + string paramType; + try + { + paramType = toFormalType(*retParam->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeName = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*retParam, "Parameter type " + (typeName ? *typeName : "") + " not supported."); + } if (retString.size() != 1) retString += ", "; retString += paramType; @@ -264,14 +306,32 @@ bool Why3Translator::visit(FunctionDefinition const& _function) { if (variable->name().empty()) error(*variable, "Unnamed return variables not yet supported."); - string varType = toFormalType(*variable->annotation().type); + string varType; + try + { + varType = toFormalType(*variable->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in return parameter not yet supported."); + } addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); } for (VariableDeclaration const* variable: _function.localVariables()) { if (variable->name().empty()) error(*variable, "Unnamed variables not yet supported."); - string varType = toFormalType(*variable->annotation().type); + string varType; + try + { + varType = toFormalType(*variable->annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(*variable, "Type " + (typeNamePtr ? *typeNamePtr : "") + "in variable declaration not yet supported."); + } addLine("let _" + variable->name() + ": ref " + varType + " = ref (of_int 0) in"); } addLine("try"); @@ -434,8 +494,15 @@ bool Why3Translator::visit(TupleExpression const& _node) bool Why3Translator::visit(UnaryOperation const& _unaryOperation) { - if (toFormalType(*_unaryOperation.annotation().type).empty()) - error(_unaryOperation, "Type not supported in unary operation."); + try + { + toFormalType(*_unaryOperation.annotation().type); + } + catch (NoFormalType &err) + { + string const* typeNamePtr = boost::get_error_info<errinfo_noFormalTypeFrom>(err); + error(_unaryOperation, "Type \"" + (typeNamePtr ? *typeNamePtr : "") + "\" supported in unary operation."); + } switch (_unaryOperation.getOperator()) { @@ -690,6 +757,20 @@ bool Why3Translator::visit(Literal const& _literal) return false; } +bool Why3Translator::visit(PragmaDirective const& _pragma) +{ + if (_pragma.tokens().empty()) + error(_pragma, "Not supported"); + else if (_pragma.literals().empty()) + error(_pragma, "Not supported"); + else if (_pragma.literals()[0] != "solidity") + error(_pragma, "Not supported"); + else if (_pragma.tokens()[0] != Token::Identifier) + error(_pragma, "A literal 'solidity' is not an identifier. Strange"); + + return false; +} + bool Why3Translator::isStateVariable(VariableDeclaration const* _var) const { return contains(m_currentContract.stateVariables, _var); diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h index 1b80ed61..4fdac385 100644 --- a/libsolidity/formal/Why3Translator.h +++ b/libsolidity/formal/Why3Translator.h @@ -60,9 +60,10 @@ private: /// Appends imports and constants use throughout the formal code. void appendPreface(); - /// @returns a string representation of the corresponding formal type or the empty string - /// if the type is not supported. + /// @returns a string representation of the corresponding formal type or throws NoFormalType exception. std::string toFormalType(Type const& _type) const; + using errinfo_noFormalTypeFrom = boost::error_info<struct tag_noFormalTypeFrom, std::string /* name of the type that cannot be translated */ >; + struct NoFormalType: virtual Exception {}; void indent() { newLine(); m_lines.back().indentation++; } void unindent(); @@ -93,6 +94,7 @@ private: virtual bool visit(IndexAccess const& _node) override; virtual bool visit(Identifier const& _node) override; virtual bool visit(Literal const& _node) override; + virtual bool visit(PragmaDirective const& _node) override; virtual bool visitNode(ASTNode const& _node) override { diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt index 755cf281..d84ee10c 100644 --- a/libsolidity/grammar.txt +++ b/libsolidity/grammar.txt @@ -77,7 +77,7 @@ Expression = | Expression? (',' Expression) | PrimaryExpression -PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | StringLiteral +PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | HexLiteral | StringLiteral FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' Expression? ( ',' Expression )* ')' NewExpression = 'new' Identifier @@ -88,8 +88,8 @@ BooleanLiteral = 'true' | 'false' NumberLiteral = '0x'? [0-9]+ (' ' NumberUnit)? NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether' | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' +HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'') StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"' - Identifier = [a-zA-Z_] [a-zA-Z_0-9]* ElementaryTypeName = 'address' | 'bool' | 'string' | 'var' diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 5c7163ee..8d2c2ed4 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -95,7 +95,9 @@ assembly::Statement Parser::parseStatement() fatalParserError("Label name / variable name must precede \":\"."); assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); m_scanner->next(); - if (m_scanner->currentToken() == Token::Assign) + // identifier:=: should be parsed as identifier: =: (i.e. a label), + // while identifier:= (being followed by a non-colon) as identifier := (assignment). + if (m_scanner->currentToken() == Token::Assign && m_scanner->peekNextToken() != Token::Colon) { // functional assignment FunctionalAssignment funAss = createWithLocation<FunctionalAssignment>(identifier.location); @@ -133,6 +135,7 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) // Allowed instructions, lowercase names. static map<string, dev::solidity::Instruction> s_instructions; if (s_instructions.empty()) + { for (auto const& instruction: solidity::c_instructions) { if ( @@ -141,24 +144,29 @@ assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) ) continue; string name = instruction.first; - if (instruction.second == solidity::Instruction::SUICIDE) - name = "selfdestruct"; transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); }); s_instructions[name] = instruction.second; } + // add alias for selfdestruct + s_instructions["selfdestruct"] = solidity::Instruction::SUICIDE; + } + Statement ret; switch (m_scanner->currentToken()) { case Token::Identifier: case Token::Return: case Token::Byte: + case Token::Address: { string literal; if (m_scanner->currentToken() == Token::Return) literal = "return"; else if (m_scanner->currentToken() == Token::Byte) literal = "byte"; + else if (m_scanner->currentToken() == Token::Address) + literal = "address"; else literal = m_scanner->currentLiteral(); // first search the set of instructions. diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index ec6b5d2e..476721db 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -302,7 +302,7 @@ dev::h256 CompilerStack::contractCodeHash(string const& _contractName) const if (obj.bytecode.empty() || !obj.linkReferences.empty()) return dev::h256(); else - return dev::sha3(obj.bytecode); + return dev::keccak256(obj.bytecode); } Json::Value CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName, StringMap _sourceCodes, bool _inJsonFormat) const diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp index 99ed75bc..1c804b78 100644 --- a/libsolidity/interface/GasEstimator.cpp +++ b/libsolidity/interface/GasEstimator.cpp @@ -136,7 +136,7 @@ GasEstimator::GasConsumption GasEstimator::functionalEstimation( ExpressionClasses& classes = state->expressionClasses(); using Id = ExpressionClasses::Id; using Ids = vector<Id>; - Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::sha3(_signature))))); + Id hashValue = classes.find(u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256(_signature))))); Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))}); classes.forceEqual(hashValue, Instruction::DIV, Ids{ calldata, diff --git a/scripts/build_emscripten.sh b/scripts/build_emscripten.sh index fe7ea11d..9b432e95 100755 --- a/scripts/build_emscripten.sh +++ b/scripts/build_emscripten.sh @@ -29,7 +29,12 @@ set -e if [[ "$OSTYPE" != "darwin"* ]]; then - date -u +"nightly.%Y.%-m.%-d" > prerelease.txt + if [ "$TRAVIS_BRANCH" = release ] + then + echo -n > prerelease.txt + else + date -u +"nightly.%Y.%-m.%-d" > prerelease.txt + fi ./scripts/travis-emscripten/install_deps.sh docker run -v $(pwd):/src trzeci/emscripten:sdk-tag-1.35.4-64bit ./scripts/travis-emscripten/build_emscripten.sh fi diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index 7c8523a8..334c62d4 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -56,6 +56,8 @@ detect_linux_distro() { elif [ -f /etc/os-release ]; then # extract 'foo' from NAME=foo, only on the line with NAME=foo DISTRO=$(sed -n -e 's/^NAME="\(.*\)\"/\1/p' /etc/os-release) + elif [ -f /etc/centos-release ]; then + DISTRO=CentOS else DISTRO='' fi @@ -329,6 +331,51 @@ case $(uname -s) in sudo apt-get -y install eth ;; + +#------------------------------------------------------------------------------ +# CentOS +# CentOS needs some more testing. This is the general idea of packages +# needed, but some tweaking/improvements can definitely happen +#------------------------------------------------------------------------------ + CentOS) + read -p "This script will heavily modify your system in order to allow for compilation of Solidity. Are you sure? [Y/N]" -n 1 -r + if [[ $REPLY =~ ^[Yy]$ ]]; then + # Make Sure we have the EPEL repos + sudo yum -y install epel-release + # Get g++ 4.8 + sudo rpm --import http://ftp.scientificlinux.org/linux/scientific/5x/x86_64/RPM-GPG-KEYs/RPM-GPG-KEY-cern + wget -O /etc/yum.repos.d/slc6-devtoolset.repo http://linuxsoft.cern.ch/cern/devtoolset/slc6-devtoolset.repo + sudo yum -y install devtoolset-2-gcc devtoolset-2-gcc-c++ devtoolset-2-binutils + + # Enable the devtoolset2 usage so global gcc/g++ become the 4.8 one. + # As per https://gist.github.com/stephenturner/e3bc5cfacc2dc67eca8b, what you should do afterwards is + # to add this line: + # source /opt/rh/devtoolset-2/enable + # to your bashrc so that this happens automatically at login + scl enable devtoolset-2 bash + + # Get cmake + sudo yum -y remove cmake + sudo yum -y install cmake3 + sudo ln -s /usr/bin/cmake3 /usr/bin/cmake + + # Get latest boost thanks to this guy: http://vicendominguez.blogspot.de/2014/04/boost-c-library-rpm-packages-for-centos.html + sudo yum -y remove boost-devel + sudo wget http://repo.enetres.net/enetres.repo -O /etc/yum.repos.d/enetres.repo + sudo yum install boost-devel + + # And finally jsoncpp + sudo yum -y install jsoncpp-devel + else + echo "Aborted CentOS Solidity Dependency Installation"; + exit 1 + fi + + ;; + + + + *) #------------------------------------------------------------------------------ diff --git a/scripts/isolateTests.py b/scripts/isolateTests.py new file mode 100755 index 00000000..fed779d3 --- /dev/null +++ b/scripts/isolateTests.py @@ -0,0 +1,24 @@ +#!/usr/bin/python +# +# This script reads C++ source files and writes all +# multi-line strings into individual files. +# This can be used to extract the Solidity test cases +# into files for e.g. fuzz testing as +# scripts/isolateTests.py tests/libsolidity/SolidityEndToEndTest.cpp + +import sys +lines = sys.stdin.read().split('\n') +inside = False +tests = [] +for l in lines: + if inside: + if l.strip().endswith(')";'): + inside = False + else: + tests[-1] += l + '\n' + else: + if l.strip().endswith('R"('): + inside = True + tests += [''] +for i in range(len(tests)): + open('test%d.sol' % i, 'w').write(tests[i]) diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index 23c374e1..7231f582 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -52,14 +52,14 @@ mv solidity solc # Determine version cd solc version=`grep -oP "PROJECT_VERSION \"?\K[0-9.]+(?=\")"? CMakeLists.txt` -commithash=`git rev-parse --short HEAD` +commithash=`git rev-parse --short=8 HEAD` committimestamp=`git show --format=%ci HEAD | head -n 1` commitdate=`git show --format=%ci HEAD | head -n 1 | cut - -b1-10 | sed -e 's/-0?/./' | sed -e 's/-0?/./'` echo "$commithash" > commit_hash.txt if [ $branch = develop ] then - debversion="$version-nightly-$commitdate-$commithash" + debversion="$version-develop-$commitdate-$commithash" else debversion="$version" echo -n > prerelease.txt # proper release diff --git a/scripts/travis-emscripten/publish_binary.sh b/scripts/travis-emscripten/publish_binary.sh index bfdf9906..e2cc1eea 100755 --- a/scripts/travis-emscripten/publish_binary.sh +++ b/scripts/travis-emscripten/publish_binary.sh @@ -33,7 +33,7 @@ set -e VER=$(cat CMakeLists.txt | grep 'set(PROJECT_VERSION' | sed -e 's/.*set(PROJECT_VERSION "\(.*\)".*/\1/') test -n "$VER" VER="v$VER" -COMMIT=$(git rev-parse --short HEAD) +COMMIT=$(git rev-parse --short=8 HEAD) DATE=$(date --date="$(git log -1 --date=iso --format=%ad HEAD)" --utc +%Y.%-m.%-d) # remove leading zeros in components - they are not semver-compatible @@ -54,21 +54,38 @@ git config user.name "travis" git config user.email "chris@ethereum.org" git checkout -B gh-pages origin/gh-pages git clean -f -d -x -# We only want one release per day and we do not want to push the same commit twice. -if ls ./bin/soljson-"$VER-nightly.$DATE"-*.js || ls ./bin/soljson-*"commit.$COMMIT.js" + + +FULLVERSION=INVALID +if [ "$TRAVIS_BRANCH" = release ] then - echo "Not publishing, we already published this version today." - exit 0 + # We only want one file with this version + if ls ./bin/soljson-"$VER+"*.js + then + echo "Not publishing, we already published this version." + exit 0 + fi + FULLVERSION="$VER+commit.$COMMIT" +elif [ "$TRAVIS_BRANCH" = develop ] +then + # We only want one release per day and we do not want to push the same commit twice. + if ls ./bin/soljson-"$VER-nightly.$DATE"*.js || ls ./bin/soljson-*"commit.$COMMIT.js" + then + echo "Not publishing, we already published this version today." + exit 0 + fi + FULLVERSION="$VER-nightly.$DATE+commit.$COMMIT" +else + echo "Not publishing, wrong branch." + exit 0 fi + # This file is assumed to be the product of the build_emscripten.sh script. -cp ../soljson.js ./bin/"soljson-$VER-nightly.$DATE+commit.$COMMIT.js" +cp ../soljson.js ./bin/"soljson-$FULLVERSION.js" node ./update cd bin -LATEST=$(ls -r soljson-v* | head -n 1) -cp "$LATEST" soljson-latest.js -cp soljson-latest.js ../soljson.js git add . git add ../soljson.js -git commit -m "Added compiler version $LATEST" +git commit -m "Added compiler version $FULLVERSION" git push origin gh-pages diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index f0a34632..2013c506 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -471,7 +471,7 @@ Allowed options)", try { po::command_line_parser cmdLineParser(_argc, _argv); - cmdLineParser.options(allOptions).positional(filesPositions).allow_unregistered(); + cmdLineParser.options(allOptions).positional(filesPositions); po::store(cmdLineParser.run(), m_args); } catch (po::error const& _exception) diff --git a/std/Token.sol b/std/Token.sol index 50d9ab7a..396dbf9e 100644 --- a/std/Token.sol +++ b/std/Token.sol @@ -2,10 +2,10 @@ contract Token { event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); - function totalSupply() constant returns (uint256 supply) {} - function balanceOf(address _owner) constant returns (uint256 balance) {} - function transfer(address _to, uint256 _value) returns (bool success) {} - function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {} - function approve(address _spender, uint256 _value) returns (bool success) {} - function allowance(address _owner, address _spender) constant returns (uint256 remaining) {} + function totalSupply() constant returns (uint256 supply); + function balanceOf(address _owner) constant returns (uint256 balance); + function transfer(address _to, uint256 _value) returns (bool success); + function transferFrom(address _from, address _to, uint256 _value) returns (bool success); + function approve(address _spender, uint256 _value) returns (bool success); + function allowance(address _owner, address _spender) constant returns (uint256 remaining); } diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp index cfc630d4..ec968058 100644 --- a/test/contracts/Wallet.cpp +++ b/test/contracts/Wallet.cpp @@ -588,7 +588,7 @@ BOOST_AUTO_TEST_CASE(revoke_addOwner) BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); // add a new owner Address deployer = m_sender; - h256 opHash = sha3(FixedHash<4>(dev::sha3("addOwner(address)")).asBytes() + h256(0x33).asBytes()); + h256 opHash = dev::keccak256(FixedHash<4>(dev::keccak256("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 = account(0); diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp index 1f216680..fc103393 100644 --- a/test/libsolidity/GasMeter.cpp +++ b/test/libsolidity/GasMeter.cpp @@ -82,7 +82,7 @@ public: { u256 gasUsed = 0; GasMeter::GasConsumption gas; - FixedHash<4> hash(dev::sha3(_sig)); + FixedHash<4> hash(dev::keccak256(_sig)); for (bytes const& arguments: _argumentVariants) { sendMessage(hash.asBytes() + arguments, false, 0); diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 8d1a1d6c..45eceb34 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -87,9 +87,14 @@ BOOST_AUTO_TEST_CASE(simple_instructions) BOOST_CHECK(successParse("{ dup1 dup1 mul dup1 sub }")); } +BOOST_AUTO_TEST_CASE(suicide_selfdestruct) +{ + BOOST_CHECK(successParse("{ suicide selfdestruct }")); +} + BOOST_AUTO_TEST_CASE(keywords) { - BOOST_CHECK(successParse("{ byte return }")); + BOOST_CHECK(successParse("{ byte return address }")); } BOOST_AUTO_TEST_CASE(constants) @@ -152,6 +157,11 @@ BOOST_AUTO_TEST_CASE(oversize_string_literals) BOOST_CHECK(!successAssemble("{ let x := \"123456789012345678901234567890123\" }")); } +BOOST_AUTO_TEST_CASE(assignment_after_tag) +{ + BOOST_CHECK(successParse("{ let x := 1 { tag: =: x } }")); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 7ee5700c..155f117f 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1260,7 +1260,7 @@ BOOST_AUTO_TEST_CASE(multiple_elementary_accessors) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("data()") == encodeArgs(8)); BOOST_CHECK(callContractFunction("name()") == encodeArgs("Celina")); - BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::sha3(bytes(1, 0x7b)))); + BOOST_CHECK(callContractFunction("a_hash()") == encodeArgs(dev::keccak256(bytes(1, 0x7b)))); BOOST_CHECK(callContractFunction("an_address()") == encodeArgs(toBigEndian(u160(0x1337)))); BOOST_CHECK(callContractFunction("super_secret_data()") == bytes()); } @@ -1342,7 +1342,7 @@ BOOST_AUTO_TEST_CASE(msg_sig) } )"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::sha3("foo(uint256)")).asBytes()))); + BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes()))); } BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same) @@ -1358,7 +1358,7 @@ BOOST_AUTO_TEST_CASE(msg_sig_after_internal_call_is_same) } )"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::sha3("foo(uint256)")).asBytes()))); + BOOST_CHECK(callContractFunction("foo(uint256)") == encodeArgs(asString(FixedHash<4>(dev::keccak256("foo(uint256)")).asBytes()))); } BOOST_AUTO_TEST_CASE(now) @@ -1686,7 +1686,7 @@ BOOST_AUTO_TEST_CASE(sha3) compileAndRun(sourceCode); auto f = [&](u256 const& _x) -> u256 { - return dev::sha3(toBigEndian(_x)); + return dev::keccak256(toBigEndian(_x)); }; testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(5)); @@ -2582,7 +2582,7 @@ BOOST_AUTO_TEST_CASE(event) BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); 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[0], dev::keccak256(string("Deposit(address,bytes32,uint256)"))); BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight)); BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id)); } @@ -2604,7 +2604,7 @@ BOOST_AUTO_TEST_CASE(event_no_arguments) BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK(m_logs[0].data.empty()); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); - BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit()"))); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()"))); } BOOST_AUTO_TEST_CASE(event_anonymous) @@ -2664,7 +2664,7 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data) BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK(m_logs[0].data == encodeArgs((u160)m_sender, id, value, true)); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); - BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,bytes32,uint256,bool)"))); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256,bool)"))); } BOOST_AUTO_TEST_CASE(event_really_lots_of_data) @@ -2681,9 +2681,9 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data) callContractFunction("deposit()"); BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); - BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 4) + FixedHash<4>(dev::sha3("deposit()")).asBytes()); + BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 4) + FixedHash<4>(dev::keccak256("deposit()")).asBytes()); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); - BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); } BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) @@ -2707,7 +2707,7 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 3, string("ABC"))); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); - BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); } BOOST_AUTO_TEST_CASE(event_indexed_string) @@ -2738,11 +2738,11 @@ BOOST_AUTO_TEST_CASE(event_indexed_string) dynx[i] = i; BOOST_CHECK(m_logs[0].data == bytes()); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); - BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::sha3(dynx)); - BOOST_CHECK_EQUAL(m_logs[0].topics[2], dev::sha3( + BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(dynx)); + BOOST_CHECK_EQUAL(m_logs[0].topics[2], dev::keccak256( encodeArgs(u256(4), u256(5), u256(6), u256(7)) )); - BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("E(string,uint256[4])"))); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(string,uint256[4])"))); } BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) @@ -2784,7 +2784,7 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13) == encodeArgs( - dev::sha3( + dev::keccak256( toBigEndian(u256(10)) + toBigEndian(u256(12)) + toBigEndian(u256(13))))); @@ -2802,7 +2802,7 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_numeric_literals) compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("foo(uint256,uint16)", 10, 12) == encodeArgs( - dev::sha3( + dev::keccak256( toBigEndian(u256(10)) + bytes{0x0, 0xc} + bytes(1, 0x91)))); @@ -2823,10 +2823,10 @@ BOOST_AUTO_TEST_CASE(sha3_multiple_arguments_with_string_literals) })"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("foo()") == encodeArgs(dev::sha3("foo"))); + BOOST_CHECK(callContractFunction("foo()") == encodeArgs(dev::keccak256("foo"))); BOOST_CHECK(callContractFunction("bar(uint256,uint16)", 10, 12) == encodeArgs( - dev::sha3( + dev::keccak256( toBigEndian(u256(10)) + bytes{0x0, 0xc} + bytes(1, 0x91) + @@ -2868,7 +2868,27 @@ BOOST_AUTO_TEST_CASE(iterated_sha3_with_bytes) )"; compileAndRun(sourceCode); BOOST_CHECK(callContractFunction("foo()") == encodeArgs( - u256(dev::sha3(bytes{'b'} + dev::sha3("xyz").asBytes() + bytes{'a'})) + u256(dev::keccak256(bytes{'b'} + dev::keccak256("xyz").asBytes() + bytes{'a'})) + )); +} + +BOOST_AUTO_TEST_CASE(keccak256_multiple_arguments) +{ + char const* sourceCode = R"( + contract c { + function foo(uint a, uint b, uint c) returns (bytes32 d) + { + d = keccak256(a, b, c); + } + })"; + compileAndRun(sourceCode); + + BOOST_CHECK(callContractFunction("foo(uint256,uint256,uint256)", 10, 12, 13) == encodeArgs( + dev::keccak256( + toBigEndian(u256(10)) + + toBigEndian(u256(12)) + + toBigEndian(u256(13)) + ) )); } @@ -3013,9 +3033,9 @@ BOOST_AUTO_TEST_CASE(bytes_from_calldata_to_memory) } )"; compileAndRun(sourceCode); - bytes calldata1 = FixedHash<4>(dev::sha3("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); + bytes calldata1 = FixedHash<4>(dev::keccak256("f()")).asBytes() + bytes(61, 0x22) + bytes(12, 0x12); sendMessage(calldata1, false); - BOOST_CHECK(m_output == encodeArgs(dev::sha3(bytes{'a', 'b', 'c'} + calldata1))); + BOOST_CHECK(m_output == encodeArgs(dev::keccak256(bytes{'a', 'b', 'c'} + calldata1))); } BOOST_AUTO_TEST_CASE(call_forward_bytes) @@ -3389,8 +3409,8 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments) )"; compileAndRun(sourceCode); - string innercalldata1 = asString(FixedHash<4>(dev::sha3("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); - string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3)); + string innercalldata1 = asString(FixedHash<4>(dev::keccak256("f(uint256,uint256)")).asBytes() + encodeArgs(8, 9)); + string innercalldata2 = asString(FixedHash<4>(dev::keccak256("g(uint256)")).asBytes() + encodeArgs(3)); bytes calldata = encodeArgs( 12, 32 * 4, u256(32 * 4 + 32 + (innercalldata1.length() + 31) / 32 * 32), 13, u256(innercalldata1.length()), innercalldata1, @@ -4668,7 +4688,7 @@ BOOST_AUTO_TEST_CASE(reusing_memory) } )"; compileAndRun(sourceCode, 0, "Main"); - BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::sha3(dev::toBigEndian(u256(0x34))))); + BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::keccak256(dev::toBigEndian(u256(0x34))))); } BOOST_AUTO_TEST_CASE(return_string) @@ -7144,6 +7164,23 @@ BOOST_AUTO_TEST_CASE(payable_function) BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 27 + 27); } +BOOST_AUTO_TEST_CASE(payable_function_calls_library) +{ + char const* sourceCode = R"( + library L { + function f() returns (uint) { return 7; } + } + contract C { + function f() payable returns (uint) { + return L.f(); + } + } + )"; + compileAndRun(sourceCode, 0, "L"); + compileAndRun(sourceCode, 0, "C", bytes(), map<string, Address>{{"L", m_contractAddress}}); + BOOST_CHECK(callContractFunctionWithValue("f()", 27) == encodeArgs(u256(7))); +} + BOOST_AUTO_TEST_CASE(non_payable_throw) { char const* sourceCode = R"( @@ -7186,6 +7223,33 @@ BOOST_AUTO_TEST_CASE(no_nonpayable_circumvention_by_modifier) BOOST_CHECK_EQUAL(balanceAt(m_contractAddress), 0); } +BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call) +{ + // This tests that memory resize for return values is not paid during the call, which would + // make the gas calculation overly complex. We access the end of the output area before + // the call is made. + // Tests that this also survives the optimizer. + char const* sourceCode = R"( + contract C { + function f() returns (uint[200]) {} + } + contract D { + function f(C c) returns (uint) { c.f(); return 7; } + } + )"; + + compileAndRun(sourceCode, 0, "C"); + u160 cAddr = m_contractAddress; + compileAndRun(sourceCode, 0, "D"); + BOOST_CHECK(callContractFunction("f(address)", cAddr) == encodeArgs(u256(7))); + + m_optimize = true; + + compileAndRun(sourceCode, 0, "C"); + u160 cAddrOpt = m_contractAddress; + compileAndRun(sourceCode, 0, "D"); + BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7))); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h index bfd87c2b..7d44edaf 100644 --- a/test/libsolidity/SolidityExecutionFramework.h +++ b/test/libsolidity/SolidityExecutionFramework.h @@ -106,7 +106,7 @@ public: template <class... Args> bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) { - FixedHash<4> hash(dev::sha3(_sig)); + FixedHash<4> hash(dev::keccak256(_sig)); sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); return m_output; } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 58736025..76141f41 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -154,7 +154,7 @@ static FunctionTypePointer retrieveFunctionBySignature( std::string const& _signature ) { - FixedHash<4> hash(dev::sha3(_signature)); + FixedHash<4> hash(dev::keccak256(_signature)); return _contract->interfaceFunctions()[hash]; } @@ -4009,6 +4009,16 @@ BOOST_AUTO_TEST_CASE(external_constructor) BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); } +BOOST_AUTO_TEST_CASE(invalid_array_as_statement) +{ + char const* text = R"( + contract test { + struct S { uint x; } + function test(uint k) { S[k]; } + } + )"; + BOOST_CHECK(expectError(text, false) == Error::Type::TypeError); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 206f23fb..562b7859 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -805,7 +805,7 @@ BOOST_AUTO_TEST_CASE(cse_empty_sha3) Instruction::SHA3 }; checkCSE(input, { - u256(sha3(bytesConstRef())) + u256(dev::keccak256(bytesConstRef())) }); } @@ -823,7 +823,7 @@ BOOST_AUTO_TEST_CASE(cse_partial_sha3) u256(0xabcd) << (256 - 16), u256(0), Instruction::MSTORE, - u256(sha3(bytes{0xab, 0xcd})) + u256(dev::keccak256(bytes{0xab, 0xcd})) }); } |