diff options
-rw-r--r-- | docs/common-patterns.rst | 104 | ||||
-rw-r--r-- | docs/contracts.rst | 11 | ||||
-rw-r--r-- | docs/control-structures.rst | 27 | ||||
-rw-r--r-- | docs/index.rst | 2 | ||||
-rw-r--r-- | docs/installing-solidity.rst | 6 | ||||
-rw-r--r-- | docs/introduction-to-smart-contracts.rst | 16 | ||||
-rw-r--r-- | docs/layout-of-source-files.rst | 10 | ||||
-rw-r--r-- | docs/miscellaneous.rst | 2 | ||||
-rw-r--r-- | docs/security-considerations.rst | 8 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 48 | ||||
-rw-r--r-- | libdevcore/Hash.cpp | 440 | ||||
-rw-r--r-- | libdevcore/Hash.h | 38 | ||||
-rw-r--r-- | libevmasm/Assembly.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 192 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.h | 23 | ||||
-rw-r--r-- | libsolidity/formal/Why3Translator.cpp | 9 | ||||
-rwxr-xr-x | scripts/travis-emscripten/publish_binary.sh | 2 | ||||
-rw-r--r-- | test/contracts/AuctionRegistrar.cpp | 1 | ||||
-rw-r--r-- | test/contracts/FixedFeeRegistrar.cpp | 1 | ||||
-rw-r--r-- | test/contracts/Wallet.cpp | 1 | ||||
-rw-r--r-- | test/libsolidity/ASTJSON.cpp | 141 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 21 |
22 files changed, 514 insertions, 591 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 322be3ef..74f9c078 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -2,6 +2,110 @@ Common Patterns ############### +.. index:: withdrawal + +.. _withdrawal_pattern: + +************************* +Withdrawal from Contracts +************************* + +The recommended method of sending funds after an effect +is using the withdrawal pattern. Although the most intuitive +method of sending Ether, as a result of an effect, is a +direct ``send`` call, this is not recommended as it +introduces a potential security risk. You may read +more about this on the :ref:`security_considerations` page. + +This is an example of the withdrawal pattern in practice in +a contract where the goal is to send the most money to the +contract in order to become the "richest", inspired by +`King of the Ether <https://www.kingoftheether.com/>`_. + +In the following contract, if you are usurped as the richest, +you will recieve the funds of the person who has gone on to +become the new richest. + +:: + + contract WithdrawalContract { + address public richest; + uint public mostSent; + + mapping (address => uint) pendingWithdrawals; + + function WithdrawalContract() { + richest = msg.sender; + mostSent = msg.value; + } + + function becomeRichest() returns (bool) { + if (msg.value > mostSent) { + pendingWithdrawals[richest] += msg.value; + richest = msg.sender; + mostSent = msg.value; + return true; + } + else { + return false; + } + } + + function withdraw() returns (bool) { + uint amount = pendingWithdrawals[msg.sender]; + // Remember to zero the pending refund before + // sending to prevent re-entrancy attacks + pendingWithdrawals[msg.sender] = 0; + if (msg.sender.send(amount)) { + return true; + } + else { + pendingWithdrawals[msg.sender] = amount; + return false; + } + } + } + +This is as opposed to the more intuitive sending pattern. + +:: + + contract SendContract { + address public richest; + uint public mostSent; + + function SendContract() { + richest = msg.sender; + mostSent = msg.value; + } + + function becomeRichest() returns (bool) { + if (msg.value > mostSent) { + // Check if call succeeds to prevent an attacker + // from trapping the previous person's funds in + // this contract through a callstack attack + if (!richest.send(msg.value)) { + throw; + } + richest = msg.sender; + mostSent = msg.value; + return true; + } + else { + return false; + } + } + } + +Notice that, in this example, an attacker could trap the +contract into an unusable state by causing ``richest`` to be +the address of a contract that has a fallback function +which consumes more than the 2300 gas stipend. That way, +whenever ``send`` is called to deliver funds to the +"poisoned" contract, it will cause execution to always fail +because there will not be enough gas to finish the execution +of the fallback function. + .. index:: access;restricting ****************** diff --git a/docs/contracts.rst b/docs/contracts.rst index 4372c278..e9fc4526 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -25,7 +25,7 @@ API, this is done as follows:: // Need to specify some source including contract name for the data param below var source = "contract CONTRACT_NAME { function CONTRACT_NAME(unit a, uint b) {} }"; - + // The json abi array generated by the compiler var abiArray = [ { @@ -967,7 +967,7 @@ custom types without the overhead of external function calls: As the compiler cannot know where the library will be deployed at, these addresses have to be filled into the final bytecode by a linker -(see :ref:`commandline-compiler`) on how to use the +(see :ref:`commandline-compiler` for how to use the commandline compiler for linking). If the addresses are not given as arguments to the compiler, the compiled hex code will contain placeholders of the form ``__Set______`` (where @@ -977,10 +977,11 @@ encoding of the address of the library contract. Restrictions for libraries in comparison to contracts: -- no state variables -- cannot inherit nor be inherited +- No state variables +- Cannot inherit nor be inherited +- Cannot recieve Ether -(these might be lifted at a later point) +(These might be lifted at a later point.) .. index:: ! using for, library diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 5b78d099..b3940f72 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -127,11 +127,11 @@ Those names will still be present on the stack, but they are inaccessible. .. _creating-contracts: -Creating Contracts via new -========================== +Creating Contracts via ``new`` +============================== A contract can create a new contract using the ``new`` keyword. The full -code of the contract to be created has to be known and thus recursive +code of the contract being created has to be known and, thus, recursive creation-dependencies are now possible. :: @@ -142,6 +142,8 @@ creation-dependencies are now possible. x = a; } } + + contract C { D d = new D(4); // will be executed as part of C's constructor @@ -299,11 +301,14 @@ In the following example, we show how ``throw`` can be used to easily revert an } } -Currently, there are three situations, where exceptions happen automatically in Solidity: +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``) +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. 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. @@ -500,9 +505,9 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly. +-------------------------+------+-----------------------------------------------------------------+ | callvalue | | wei sent together with the current call | +-------------------------+------+-----------------------------------------------------------------+ -| calldataload(p) | | call data starting from position p (32 bytes) | +| calldataload(p) | | calldata starting from position p (32 bytes) | +-------------------------+------+-----------------------------------------------------------------+ -| calldatasize | | size of call data in bytes | +| calldatasize | | size of calldata in bytes | +-------------------------+------+-----------------------------------------------------------------+ | calldatacopy(t, f, s) | `-` | copy s bytes from calldata at position f to mem at position t | +-------------------------+------+-----------------------------------------------------------------+ @@ -517,14 +522,14 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly. | create(v, p, s) | | create new contract with code mem[p..(p+s)) and send v wei | | | | and return the new address | +-------------------------+------+-----------------------------------------------------------------+ -| call(g, a, v, in, | | call contract at address a with input mem[in..(in+insize)] | +| call(g, a, v, in, | | call contract at address a with input mem[in..(in+insize)) | | insize, out, outsize) | | providing g gas and v wei and output area | -| | | mem[out..(out+outsize)] returting 1 on error (out of gas) | +| | | mem[out..(out+outsize)) returning 1 on error (out of gas) | +-------------------------+------+-----------------------------------------------------------------+ -| callcode(g, a, v, in, | | identical to call but only use the code from a and stay | +| callcode(g, a, v, in, | | identical to `call` but only use the code from a and stay | | insize, out, outsize) | | in the context of the current contract otherwise | +-------------------------+------+-----------------------------------------------------------------+ -| delegatecall(g, a, in, | | identical to callcode but also keep ``caller`` | +| delegatecall(g, a, in, | | identical to `callcode` but also keep ``caller`` | | insize, out, outsize) | | and ``callvalue`` | +-------------------------+------+-----------------------------------------------------------------+ | return(p, s) | `*` | end execution, return data mem[p..(p+s)) | diff --git a/docs/index.rst b/docs/index.rst index 4b3ace89..a330172e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -70,7 +70,7 @@ 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. diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index 47388c25..ba40c99f 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -73,7 +73,7 @@ to compile Solidity on Ubuntu 14.04 (Trusty Tahr). sudo apt-get -y install build-essential git cmake libgmp-dev libboost-all-dev \ libjsoncpp-dev - + sudo add-apt-repository -y ppa:ethereum/ethereum sudo add-apt-repository -y ppa:ethereum/ethereum-dev sudo apt-get -y update @@ -94,14 +94,14 @@ installed either by adding the Ethereum PPA (Option 1) or by backporting sudo apt-get -y install build-essential git cmake libgmp-dev libboost-all-dev \ libjsoncpp-dev - + # (Option 1) For those willing to add the Ethereum PPA: sudo add-apt-repository -y ppa:ethereum/ethereum sudo add-apt-repository -y ppa:ethereum/ethereum-dev sudo apt-get -y update sudo apt-get -y upgrade sudo apt-get -y install libcryptopp-dev - + ## (Option 2) For those willing to backport libcrypto++: #sudo apt-get -y install ubuntu-dev-tools #sudo pbuilder create diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 0122387b..fbce4244 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -95,7 +95,7 @@ registering with username and password - all you need is an Ethereum keypair. This contract introduces some new concepts, let us go through them one by one. The line ``address public minter;`` declares a state variable of type address -that is publicly accessible. The ``address`` type is a 160 bit value +that is publicly accessible. The ``address`` type is a 160-bit value that does not allow any arithmetic operations. It is suitable for storing addresses of contracts or keypairs belonging to external persons. The keyword ``public`` automatically generates a function that @@ -220,7 +220,7 @@ only the person holding the keys to the account can transfer money from it. Blocks ====== -One major obstacle to overcome is what in bitcoin terms is called "double-spend attack": +One major obstacle to overcome is what, in Bitcoin terms, is called "double-spend attack": What happens if two transactions exist in the network that both want to empty an account, a so-called conflict? @@ -236,7 +236,7 @@ Ethereum this is roughly every 17 seconds. As part of the "order selection mechanism" (which is called "mining") it may happen that blocks are reverted from time to time, but only at the "tip" of the chain. The more -blocks are reverted the less likely it is. So it might be that your transactions +blocks that are added on top, the less likely it is. So it might be that your transactions are reverted and even removed from the blockchain, but the longer you wait, the less likely it will be. @@ -277,7 +277,7 @@ of transactions sent from that address, the so-called "nonce"). Apart from the fact whether an account stores code or not, the EVM treats the two types equally, though. -Every account has a persistent key-value store mapping 256 bit words to 256 bit +Every account has a persistent key-value store mapping 256-bit words to 256-bit words called **storage**. Furthermore, every account has a **balance** in @@ -300,7 +300,7 @@ If the target account is the zero-account (the account with the address ``0``), the transaction creates a **new contract**. As already mentioned, the address of that contract is not the zero address but an address derived from the sender and -its number of transaction sent (the "nonce"). The payload +its number of transactions sent (the "nonce"). The payload of such a contract creation transaction is taken to be EVM bytecode and executed. The output of this execution is permanently stored as the code of the contract. @@ -332,7 +332,7 @@ Storage, Memory and the Stack ============================= Each account has a persistent memory area which is called **storage**. -Storage is a key-value store that maps 256 bit words to 256 bit words. +Storage is a key-value store that maps 256-bit words to 256-bit words. It is not possible to enumerate storage from within a contract and it is comparatively costly to read and even more so, to modify storage. A contract can neither read nor write to any storage apart @@ -340,7 +340,7 @@ from its own. The second memory area is called **memory**, of which a contract obtains a freshly cleared instance for each message call. Memory can be -addressed at byte level, but read and written to in 32 byte (256 bit) +addressed at byte level, but read and written to in 32 byte (256-bit) chunks. Memory is more costly the larger it grows (it scales quadratically). @@ -364,7 +364,7 @@ Instruction Set The instruction set of the EVM is kept minimal in order to avoid incorrect implementations which could cause consensus problems. -All instructions operate on the basic data type, 256 bit words. +All instructions operate on the basic data type, 256-bit words. The usual arithmetic, bit, logical and comparison operations are present. Conditional and unconditional jumps are possible. Furthermore, contracts can access relevant properties of the current block diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index ef6fd656..6ef06961 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -61,7 +61,7 @@ It depends on the compiler (see below) how to actually resolve the paths. In general, the directory hierarchy does not need to strictly map onto your local filesystem, it can also map to resources discovered via e.g. ipfs, http or git. -Use in actual Compilers +Use in Actual Compilers ----------------------- When the compiler is invoked, it is not only possible to specify how to @@ -101,7 +101,7 @@ and then run the compiler as As a more complex example, suppose you rely on some module that uses a very old version of dapp-bin. That old version of dapp-bin is checked -out at ``/usr/local/dapp-bin_old``, then you can use +out at ``/usr/local/dapp-bin_old``, then you can use .. code-block:: bash @@ -171,9 +171,9 @@ for the two input parameters and two returned values. * @return s The calculated surface. * @return p The calculated perimeter. */ - function rectangle(uint w, uint h) returns (uint s, uint p){ - s = w*h; - p = 2*(w+h); + function rectangle(uint w, uint h) returns (uint s, uint p) { + s = w * h; + p = 2 * (w + h); } } diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 804d69ef..882a6002 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -66,7 +66,7 @@ Calling ``select(false, x)`` will compute ``x * x`` and ``select(true, x)`` will .. index:: optimizer, common subexpression elimination, constant propagation ************************* -Internals - the Optimizer +Internals - The Optimizer ************************* The Solidity optimizer operates on assembly, so it can be and also is used by other languages. It splits the sequence of instructions into basic blocks at JUMPs and JUMPDESTs. Inside these blocks, the instructions are analysed and every modification to the stack, to memory or storage is recorded as an expression which consists of an instruction and a list of arguments which are essentially pointers to other expressions. The main idea is now to find expressions that are always equal (on every input) and combine them into an expression class. The optimizer first tries to find each new expression in a list of already known expressions. If this does not work, the expression is simplified according to rules like ``constant + constant = sum_of_constants`` or ``X * 1 = X``. Since this is done recursively, we can also apply the latter rule if the second factor is a more complex expression where we know that it will always evaluate to one. Modifications to storage and memory locations have to erase knowledge about storage and memory locations which are not known to be different: If we first write to location x and then to location y and both are input variables, the second could overwrite the first, so we actually do not know what is stored at x after we wrote to y. On the other hand, if a simplification of the expression x - y evaluates to a non-zero constant, we know that we can keep our knowledge about what is stored at x. diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index bae6e20b..f8d099e4 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -1,3 +1,5 @@ +.. _security_considerations: + ####################### Security Considerations ####################### @@ -124,7 +126,7 @@ Sending and Receiving Ether 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. + a :ref:`"withdraw" pattern instead of a "send" pattern <withdrawal_pattern>`. Callstack Depth =============== @@ -145,7 +147,7 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like :: - contract TxUserWallet { + contract TxUserWallet { address owner; function TxUserWallet() { @@ -162,7 +164,7 @@ Now someone tricks you into sending ether to the address of this attack wallet: :: - contract TxAttackWallet { + contract TxAttackWallet { address owner; function TxAttackWallet() { diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 7dd51f00..61589b2e 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -191,6 +191,8 @@ contract into a blind auction where it is not possible to see the actual bid until the bidding period ends. +.. _simple_auction: + Simple Open Auction =================== @@ -269,7 +271,7 @@ activate themselves. // highestBidder.send(highestBid) is a security risk // because it can be prevented by the caller by e.g. // raising the call stack to 1023. It is always safer - // to let the recipient withdraw their money themselves. + // to let the recipient withdraw their money themselves. pendingReturns[highestBidder] += highestBid; } highestBidder = msg.sender; @@ -278,14 +280,21 @@ activate themselves. } /// Withdraw a bid that was overbid. - function withdraw() { + function withdraw() returns (bool) { 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. - pendingReturns[msg.sender] = 0; - if (!msg.sender.send(amount)) - throw; // If anything fails, this will revert the changes above + if (amount > 0) { + // 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. + pendingReturns[msg.sender] = 0; + + if (!msg.sender.send(amount)) { + // No need to call throw here, just reset the amount owing + pendingReturns[msg.sender] = amount; + return false; + } + } + return true; } /// End the auction and send the highest bid @@ -489,15 +498,22 @@ high or low invalid bids. } /// Withdraw a bid that was overbid. - function withdraw() { + function withdraw() returns (bool) { 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 (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 + if (amount > 0) { + // 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 (see the remark above about + // conditions -> effects -> interaction). + pendingReturns[msg.sender] = 0; + + if (!msg.sender.send(amount)){ + // No need to call throw here, just reset the amount owing + pendingReturns[msg.sender] = amount; + return false; + } + } + return true; } /// End the auction and send the highest bid diff --git a/libdevcore/Hash.cpp b/libdevcore/Hash.cpp deleted file mode 100644 index c6b917b9..00000000 --- a/libdevcore/Hash.cpp +++ /dev/null @@ -1,440 +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 Hash.cpp - * @author Gav Wood <i@gavwood.com> - * @date 2014 - */ - -#include "Hash.h" -#include <cstdio> -#include <cstdlib> -#include <cstring> -#include "picosha2.h" -using namespace std; -using namespace dev; - -namespace dev -{ - -h256 sha256(bytesConstRef _input) -{ - h256 ret; - picosha2::hash256(_input.begin(), _input.end(), ret.data(), ret.data() + 32); - return ret; -} - -namespace rmd160 -{ - -/********************************************************************\ - * - * FILE: rmd160.h - * FILE: rmd160.c - * - * CONTENTS: Header file for a sample C-implementation of the - * RIPEMD-160 hash-function. - * TARGET: any computer with an ANSI C compiler - * - * AUTHOR: Antoon Bosselaers, ESAT-COSIC - * DATE: 1 March 1996 - * VERSION: 1.0 - * - * Copyright (c) Katholieke Universiteit Leuven - * 1996, All Rights Reserved - * - \********************************************************************/ - -// Adapted into "header-only" format by Gav Wood. - -/* macro definitions */ - -#define RMDsize 160 - -/* collect four bytes into one word: */ -#define BYTES_TO_DWORD(strptr) \ -(((uint32_t) *((strptr)+3) << 24) | \ -((uint32_t) *((strptr)+2) << 16) | \ -((uint32_t) *((strptr)+1) << 8) | \ -((uint32_t) *(strptr))) - -/* ROL(x, n) cyclically rotates x over n bits to the left */ -/* x must be of an unsigned 32 bits type and 0 <= n < 32. */ -#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n)))) - -/* the five basic functions F(), G() and H() */ -#define F(x, y, z) ((x) ^ (y) ^ (z)) -#define G(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define H(x, y, z) (((x) | ~(y)) ^ (z)) -#define I(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define J(x, y, z) ((x) ^ ((y) | ~(z))) - -/* the ten basic operations FF() through III() */ -#define FF(a, b, c, d, e, x, s) {\ -(a) += F((b), (c), (d)) + (x);\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define GG(a, b, c, d, e, x, s) {\ -(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define HH(a, b, c, d, e, x, s) {\ -(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define II(a, b, c, d, e, x, s) {\ -(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define JJ(a, b, c, d, e, x, s) {\ -(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define FFF(a, b, c, d, e, x, s) {\ -(a) += F((b), (c), (d)) + (x);\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define GGG(a, b, c, d, e, x, s) {\ -(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define HHH(a, b, c, d, e, x, s) {\ -(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define III(a, b, c, d, e, x, s) {\ -(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} -#define JJJ(a, b, c, d, e, x, s) {\ -(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ -(a) = ROL((a), (s)) + (e);\ -(c) = ROL((c), 10);\ -} - -void MDinit(uint32_t *MDbuf) -{ - MDbuf[0] = 0x67452301UL; - MDbuf[1] = 0xefcdab89UL; - MDbuf[2] = 0x98badcfeUL; - MDbuf[3] = 0x10325476UL; - MDbuf[4] = 0xc3d2e1f0UL; - - return; -} - -/********************************************************************/ - -void MDcompress(uint32_t *MDbuf, uint32_t *X) -{ - uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], - dd = MDbuf[3], ee = MDbuf[4]; - uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], - ddd = MDbuf[3], eee = MDbuf[4]; - - /* round 1 */ - FF(aa, bb, cc, dd, ee, X[ 0], 11); - FF(ee, aa, bb, cc, dd, X[ 1], 14); - FF(dd, ee, aa, bb, cc, X[ 2], 15); - FF(cc, dd, ee, aa, bb, X[ 3], 12); - FF(bb, cc, dd, ee, aa, X[ 4], 5); - FF(aa, bb, cc, dd, ee, X[ 5], 8); - FF(ee, aa, bb, cc, dd, X[ 6], 7); - FF(dd, ee, aa, bb, cc, X[ 7], 9); - FF(cc, dd, ee, aa, bb, X[ 8], 11); - FF(bb, cc, dd, ee, aa, X[ 9], 13); - FF(aa, bb, cc, dd, ee, X[10], 14); - FF(ee, aa, bb, cc, dd, X[11], 15); - FF(dd, ee, aa, bb, cc, X[12], 6); - FF(cc, dd, ee, aa, bb, X[13], 7); - FF(bb, cc, dd, ee, aa, X[14], 9); - FF(aa, bb, cc, dd, ee, X[15], 8); - - /* round 2 */ - GG(ee, aa, bb, cc, dd, X[ 7], 7); - GG(dd, ee, aa, bb, cc, X[ 4], 6); - GG(cc, dd, ee, aa, bb, X[13], 8); - GG(bb, cc, dd, ee, aa, X[ 1], 13); - GG(aa, bb, cc, dd, ee, X[10], 11); - GG(ee, aa, bb, cc, dd, X[ 6], 9); - GG(dd, ee, aa, bb, cc, X[15], 7); - GG(cc, dd, ee, aa, bb, X[ 3], 15); - GG(bb, cc, dd, ee, aa, X[12], 7); - GG(aa, bb, cc, dd, ee, X[ 0], 12); - GG(ee, aa, bb, cc, dd, X[ 9], 15); - GG(dd, ee, aa, bb, cc, X[ 5], 9); - GG(cc, dd, ee, aa, bb, X[ 2], 11); - GG(bb, cc, dd, ee, aa, X[14], 7); - GG(aa, bb, cc, dd, ee, X[11], 13); - GG(ee, aa, bb, cc, dd, X[ 8], 12); - - /* round 3 */ - HH(dd, ee, aa, bb, cc, X[ 3], 11); - HH(cc, dd, ee, aa, bb, X[10], 13); - HH(bb, cc, dd, ee, aa, X[14], 6); - HH(aa, bb, cc, dd, ee, X[ 4], 7); - HH(ee, aa, bb, cc, dd, X[ 9], 14); - HH(dd, ee, aa, bb, cc, X[15], 9); - HH(cc, dd, ee, aa, bb, X[ 8], 13); - HH(bb, cc, dd, ee, aa, X[ 1], 15); - HH(aa, bb, cc, dd, ee, X[ 2], 14); - HH(ee, aa, bb, cc, dd, X[ 7], 8); - HH(dd, ee, aa, bb, cc, X[ 0], 13); - HH(cc, dd, ee, aa, bb, X[ 6], 6); - HH(bb, cc, dd, ee, aa, X[13], 5); - HH(aa, bb, cc, dd, ee, X[11], 12); - HH(ee, aa, bb, cc, dd, X[ 5], 7); - HH(dd, ee, aa, bb, cc, X[12], 5); - - /* round 4 */ - II(cc, dd, ee, aa, bb, X[ 1], 11); - II(bb, cc, dd, ee, aa, X[ 9], 12); - II(aa, bb, cc, dd, ee, X[11], 14); - II(ee, aa, bb, cc, dd, X[10], 15); - II(dd, ee, aa, bb, cc, X[ 0], 14); - II(cc, dd, ee, aa, bb, X[ 8], 15); - II(bb, cc, dd, ee, aa, X[12], 9); - II(aa, bb, cc, dd, ee, X[ 4], 8); - II(ee, aa, bb, cc, dd, X[13], 9); - II(dd, ee, aa, bb, cc, X[ 3], 14); - II(cc, dd, ee, aa, bb, X[ 7], 5); - II(bb, cc, dd, ee, aa, X[15], 6); - II(aa, bb, cc, dd, ee, X[14], 8); - II(ee, aa, bb, cc, dd, X[ 5], 6); - II(dd, ee, aa, bb, cc, X[ 6], 5); - II(cc, dd, ee, aa, bb, X[ 2], 12); - - /* round 5 */ - JJ(bb, cc, dd, ee, aa, X[ 4], 9); - JJ(aa, bb, cc, dd, ee, X[ 0], 15); - JJ(ee, aa, bb, cc, dd, X[ 5], 5); - JJ(dd, ee, aa, bb, cc, X[ 9], 11); - JJ(cc, dd, ee, aa, bb, X[ 7], 6); - JJ(bb, cc, dd, ee, aa, X[12], 8); - JJ(aa, bb, cc, dd, ee, X[ 2], 13); - JJ(ee, aa, bb, cc, dd, X[10], 12); - JJ(dd, ee, aa, bb, cc, X[14], 5); - JJ(cc, dd, ee, aa, bb, X[ 1], 12); - JJ(bb, cc, dd, ee, aa, X[ 3], 13); - JJ(aa, bb, cc, dd, ee, X[ 8], 14); - JJ(ee, aa, bb, cc, dd, X[11], 11); - JJ(dd, ee, aa, bb, cc, X[ 6], 8); - JJ(cc, dd, ee, aa, bb, X[15], 5); - JJ(bb, cc, dd, ee, aa, X[13], 6); - - /* parallel round 1 */ - JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); - JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); - JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); - JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); - JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); - JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); - JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); - JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); - JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); - JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); - JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); - JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); - - /* parallel round 2 */ - III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); - III(ddd, eee, aaa, bbb, ccc, X[11], 13); - III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); - III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); - III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); - III(eee, aaa, bbb, ccc, ddd, X[13], 8); - III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); - III(ccc, ddd, eee, aaa, bbb, X[10], 11); - III(bbb, ccc, ddd, eee, aaa, X[14], 7); - III(aaa, bbb, ccc, ddd, eee, X[15], 7); - III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); - III(ddd, eee, aaa, bbb, ccc, X[12], 7); - III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); - III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); - III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); - III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); - - /* parallel round 3 */ - HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); - HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); - HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); - HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); - HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); - HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); - HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); - HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); - HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); - HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); - HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); - HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); - HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); - HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); - HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); - HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); - - /* parallel round 4 */ - GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); - GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); - GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); - GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); - GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); - GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); - GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); - GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); - GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); - GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); - GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); - GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); - GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); - GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); - GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); - GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); - - /* parallel round 5 */ - FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); - FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); - FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); - FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); - FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); - FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); - FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); - FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); - FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); - FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); - FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); - FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); - FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); - FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); - FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); - FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); - - /* combine results */ - ddd += cc + MDbuf[1]; /* final result for MDbuf[0] */ - MDbuf[1] = MDbuf[2] + dd + eee; - MDbuf[2] = MDbuf[3] + ee + aaa; - MDbuf[3] = MDbuf[4] + aa + bbb; - MDbuf[4] = MDbuf[0] + bb + ccc; - MDbuf[0] = ddd; - - return; -} - -void MDfinish(uint32_t *MDbuf, byte const *strptr, uint32_t lswlen, uint32_t mswlen) -{ - unsigned int i; /* counter */ - uint32_t X[16]; /* message words */ - - memset(X, 0, 16*sizeof(uint32_t)); - - /* put bytes from strptr into X */ - for (i=0; i<(lswlen&63); i++) { - /* byte i goes into word X[i div 4] at pos. 8*(i mod 4) */ - X[i>>2] ^= (uint32_t) *strptr++ << (8 * (i&3)); - } - - /* append the bit m_n == 1 */ - X[(lswlen>>2)&15] ^= (uint32_t)1 << (8*(lswlen&3) + 7); - - if ((lswlen & 63) > 55) { - /* length goes to next block */ - MDcompress(MDbuf, X); - memset(X, 0, 16*sizeof(uint32_t)); - } - - /* append length in bits*/ - X[14] = lswlen << 3; - X[15] = (lswlen >> 29) | (mswlen << 3); - MDcompress(MDbuf, X); - - return; -} - -#undef ROL -#undef F -#undef G -#undef H -#undef I -#undef J -#undef FF -#undef GG -#undef HH -#undef II -#undef JJ -#undef FFF -#undef GGG -#undef HHH -#undef III -#undef JJJ - -} - -/* - * @returns RMD(_input) - */ -h160 ripemd160(bytesConstRef _input) -{ - h160 hashcode; - uint32_t buffer[RMDsize / 32]; // contains (A, B, C, D(, E)) - uint32_t current[16]; // current 16-word chunk - - // initialize - rmd160::MDinit(buffer); - byte const* message = _input.data(); - uint32_t remaining = _input.size(); // # of bytes not yet processed - - // process message in 16x 4-byte chunks - for (; remaining >= 64; remaining -= 64) - { - for (unsigned i = 0; i < 16; i++) - { - current[i] = BYTES_TO_DWORD(message); - message += 4; - } - rmd160::MDcompress(buffer, current); - } - // length mod 64 bytes left - - // finish: - rmd160::MDfinish(buffer, message, _input.size(), 0); - - for (unsigned i = 0; i < RMDsize / 8; i += 4) - { - hashcode[i] = buffer[i >> 2]; // implicit cast to byte - hashcode[i + 1] = (buffer[i >> 2] >> 8); //extracts the 8 least - hashcode[i + 2] = (buffer[i >> 2] >> 16); // significant bits. - hashcode[i + 3] = (buffer[i >> 2] >> 24); - } - - return hashcode; -} - -#undef BYTES_TO_DWORD -#undef RMDsize - -} diff --git a/libdevcore/Hash.h b/libdevcore/Hash.h deleted file mode 100644 index d4401014..00000000 --- a/libdevcore/Hash.h +++ /dev/null @@ -1,38 +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 Hash.h - * @author Gav Wood <i@gavwood.com> - * @date 2014 - * - * The FixedHash fixed-size "hash" container type. - */ - -#pragma once - -#include <string> -#include "FixedHash.h" -#include "vector_ref.h" -#include "SHA3.h" - -namespace dev -{ - -h256 sha256(bytesConstRef _input); - -h160 ripemd160(bytesConstRef _input); - -} diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 2024b1e9..c7822819 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -123,7 +123,7 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " " << instructionInfo(i.instruction()).name << "\t" << i.getJumpTypeAsString(); break; case Push: - _out << " PUSH " << hex << i.data(); + _out << " PUSH" << dec << max<unsigned>(1, dev::bytesRequired(i.data())) << " 0x" << hex << i.data(); break; case PushString: _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index c4134f4e..35fd0b7d 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -31,21 +31,10 @@ namespace dev namespace solidity { -void ASTJsonConverter::addKeyValue(Json::Value& _obj, string const& _key, string const& _val) -{ - // special handling for booleans - if (_key == "const" || _key == "public" || _key == "local" || - _key == "lvalue" || _key == "local_lvalue" || _key == "prefix") - _obj[_key] = (_val == "1") ? true : false; - else - // else simply add it as a string - _obj[_key] = _val; -} - void ASTJsonConverter::addJsonNode( ASTNode const& _node, string const& _nodeName, - initializer_list<pair<string const, string const>> _list, + initializer_list<pair<string const, Json::Value const>> _attributes, bool _hasChildren = false ) { @@ -54,11 +43,11 @@ void ASTJsonConverter::addJsonNode( node["id"] = reinterpret_cast<Json::UInt64>(&_node); node["src"] = sourceLocationToString(_node.location()); node["name"] = _nodeName; - if (_list.size() != 0) + if (_attributes.size() != 0) { Json::Value attrs; - for (auto& e: _list) - addKeyValue(attrs, e.first, e.second); + for (auto& e: _attributes) + attrs[e.first] = e.second; node["attributes"] = attrs; } @@ -89,11 +78,6 @@ ASTJsonConverter::ASTJsonConverter( map<string, unsigned> _sourceIndices ): m_ast(&_ast), m_sourceIndices(_sourceIndices) { - Json::Value children(Json::arrayValue); - - m_astJson["name"] = "root"; - m_astJson["children"] = children; - m_jsonNodePtrs.push(&m_astJson["children"]); } void ASTJsonConverter::print(ostream& _stream) @@ -108,21 +92,64 @@ Json::Value const& ASTJsonConverter::json() return m_astJson; } +bool ASTJsonConverter::visit(SourceUnit const&) +{ + Json::Value children(Json::arrayValue); + + m_astJson["name"] = "SourceUnit"; + m_astJson["children"] = children; + m_jsonNodePtrs.push(&m_astJson["children"]); + + return true; +} + bool ASTJsonConverter::visit(ImportDirective const& _node) { - addJsonNode(_node, "Import", { make_pair("file", _node.path())}); + addJsonNode(_node, "ImportDirective", { make_pair("file", _node.path())}); return true; } bool ASTJsonConverter::visit(ContractDefinition const& _node) { - addJsonNode(_node, "Contract", { make_pair("name", _node.name()) }, true); + Json::Value linearizedBaseContracts(Json::arrayValue); + for (auto const& baseContract: _node.annotation().linearizedBaseContracts) + linearizedBaseContracts.append(reinterpret_cast<Json::UInt64>(baseContract)); + addJsonNode(_node, "ContractDefinition", { + make_pair("name", _node.name()), + make_pair("isLibrary", _node.isLibrary()), + make_pair("fullyImplemented", _node.annotation().isFullyImplemented), + make_pair("linearizedBaseContracts", linearizedBaseContracts), + }, true); + return true; +} + +bool ASTJsonConverter::visit(InheritanceSpecifier const& _node) +{ + addJsonNode(_node, "InheritanceSpecifier", {}, true); + return true; +} + +bool ASTJsonConverter::visit(UsingForDirective const& _node) +{ + addJsonNode(_node, "UsingForDirective", {}, true); return true; } bool ASTJsonConverter::visit(StructDefinition const& _node) { - addJsonNode(_node, "Struct", { make_pair("name", _node.name()) }, true); + addJsonNode(_node, "StructDefinition", { make_pair("name", _node.name()) }, true); + return true; +} + +bool ASTJsonConverter::visit(EnumDefinition const& _node) +{ + addJsonNode(_node, "EnumDefinition", { make_pair("name", _node.name()) }, true); + return true; +} + +bool ASTJsonConverter::visit(EnumValue const& _node) +{ + addJsonNode(_node, "EnumValue", { make_pair("name", _node.name()) }); return true; } @@ -134,11 +161,11 @@ bool ASTJsonConverter::visit(ParameterList const& _node) bool ASTJsonConverter::visit(FunctionDefinition const& _node) { - addJsonNode(_node, "Function", - { make_pair("name", _node.name()), - make_pair("public", boost::lexical_cast<std::string>(_node.isPublic())), - make_pair("const", boost::lexical_cast<std::string>(_node.isDeclaredConst())) }, - true); + addJsonNode(_node, "FunctionDefinition", { + make_pair("name", _node.name()), + make_pair("public", _node.isPublic()), + make_pair("constant", _node.isDeclaredConst()) + }, true); return true; } @@ -146,16 +173,34 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) { addJsonNode(_node, "VariableDeclaration", { make_pair("name", _node.name()), - make_pair("name", _node.name()), + make_pair("type", type(_node)) }, true); return true; } +bool ASTJsonConverter::visit(ModifierDefinition const& _node) +{ + addJsonNode(_node, "ModifierDefinition", { make_pair("name", _node.name()) }, true); + return true; +} + +bool ASTJsonConverter::visit(ModifierInvocation const& _node) +{ + addJsonNode(_node, "ModifierInvocation", {}, true); + return true; +} + bool ASTJsonConverter::visit(TypeName const&) { return true; } +bool ASTJsonConverter::visit(EventDefinition const& _node) +{ + addJsonNode(_node, "EventDefinition", { make_pair("name", _node.name()) }, true); + return true; +} + bool ASTJsonConverter::visit(ElementaryTypeName const& _node) { addJsonNode(_node, "ElementaryTypeName", { make_pair("name", _node.typeName().toString()) }); @@ -176,6 +221,12 @@ bool ASTJsonConverter::visit(Mapping const& _node) return true; } +bool ASTJsonConverter::visit(ArrayTypeName const& _node) +{ + addJsonNode(_node, "ArrayTypeName", {}, true); + return true; +} + bool ASTJsonConverter::visit(InlineAssembly const& _node) { addJsonNode(_node, "InlineAssembly", {}, true); @@ -188,6 +239,12 @@ bool ASTJsonConverter::visit(Block const& _node) return true; } +bool ASTJsonConverter::visit(PlaceholderStatement const& _node) +{ + addJsonNode(_node, "PlaceholderStatement", {}); + return true; +} + bool ASTJsonConverter::visit(IfStatement const& _node) { addJsonNode(_node, "IfStatement", {}, true); @@ -232,7 +289,7 @@ bool ASTJsonConverter::visit(Throw const& _node) bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node) { - addJsonNode(_node, "VariableDefinition", {}, true); + addJsonNode(_node, "VariableDefinitionStatement", {}, true); return true; } @@ -266,7 +323,7 @@ bool ASTJsonConverter::visit(TupleExpression const& _node) bool ASTJsonConverter::visit(UnaryOperation const& _node) { addJsonNode(_node, "UnaryOperation", - { make_pair("prefix", boost::lexical_cast<std::string>(_node.isPrefixOperation())), + { make_pair("prefix", _node.isPrefixOperation()), make_pair("operator", Token::toString(_node.getOperator())), make_pair("type", type(_node)) }, true); @@ -285,7 +342,7 @@ bool ASTJsonConverter::visit(BinaryOperation const& _node) bool ASTJsonConverter::visit(FunctionCall const& _node) { addJsonNode(_node, "FunctionCall", { - make_pair("type_conversion", boost::lexical_cast<std::string>(_node.annotation().isTypeConversion)), + make_pair("type_conversion", _node.annotation().isTypeConversion), make_pair("type", type(_node)) }, true); return true; @@ -299,10 +356,10 @@ bool ASTJsonConverter::visit(NewExpression const& _node) bool ASTJsonConverter::visit(MemberAccess const& _node) { - addJsonNode(_node, "MemberAccess", - { make_pair("member_name", _node.memberName()), - make_pair("type", type(_node)) }, - true); + addJsonNode(_node, "MemberAccess", { + make_pair("member_name", _node.memberName()), + make_pair("type", type(_node)) + }, true); return true; } @@ -321,21 +378,29 @@ bool ASTJsonConverter::visit(Identifier const& _node) bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node) { - addJsonNode(_node, "ElementaryTypenameExpression", - { make_pair("value", _node.typeName().toString()), make_pair("type", type(_node)) }); + addJsonNode(_node, "ElementaryTypenameExpression", { + make_pair("value", _node.typeName().toString()), + make_pair("type", type(_node)) + }); return true; } bool ASTJsonConverter::visit(Literal const& _node) { char const* tokenString = Token::toString(_node.token()); - addJsonNode(_node, "Literal", - { make_pair("string", (tokenString) ? tokenString : "null"), - make_pair("value", _node.value()), - make_pair("type", type(_node)) }); + addJsonNode(_node, "Literal", { + make_pair("string", tokenString ? tokenString : Json::Value()), + make_pair("value", _node.value()), + make_pair("type", type(_node)) + }); return true; } +void ASTJsonConverter::endVisit(SourceUnit const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(ImportDirective const&) { } @@ -345,11 +410,30 @@ void ASTJsonConverter::endVisit(ContractDefinition const&) goUp(); } +void ASTJsonConverter::endVisit(InheritanceSpecifier const&) +{ + goUp(); +} + +void ASTJsonConverter::endVisit(UsingForDirective const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(StructDefinition const&) { goUp(); } +void ASTJsonConverter::endVisit(EnumDefinition const&) +{ + goUp(); +} + +void ASTJsonConverter::endVisit(EnumValue const&) +{ +} + void ASTJsonConverter::endVisit(ParameterList const&) { goUp(); @@ -365,6 +449,21 @@ void ASTJsonConverter::endVisit(VariableDeclaration const&) goUp(); } +void ASTJsonConverter::endVisit(ModifierDefinition const&) +{ + goUp(); +} + +void ASTJsonConverter::endVisit(ModifierInvocation const&) +{ + goUp(); +} + +void ASTJsonConverter::endVisit(EventDefinition const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(TypeName const&) { } @@ -382,6 +481,11 @@ void ASTJsonConverter::endVisit(Mapping const&) goUp(); } +void ASTJsonConverter::endVisit(ArrayTypeName const&) +{ + goUp(); +} + void ASTJsonConverter::endVisit(InlineAssembly const&) { goUp(); @@ -392,6 +496,10 @@ void ASTJsonConverter::endVisit(Block const&) goUp(); } +void ASTJsonConverter::endVisit(PlaceholderStatement const&) +{ +} + void ASTJsonConverter::endVisit(IfStatement const&) { goUp(); diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index ca4d9c2d..97aa8654 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -51,18 +51,28 @@ public: void print(std::ostream& _stream); Json::Value const& json(); + bool visit(SourceUnit const& _node) override; bool visit(ImportDirective const& _node) override; bool visit(ContractDefinition const& _node) override; + bool visit(InheritanceSpecifier const& _node) override; + bool visit(UsingForDirective const& _node) override; bool visit(StructDefinition const& _node) override; + bool visit(EnumDefinition const& _node) override; + bool visit(EnumValue const& _node) override; bool visit(ParameterList const& _node) override; bool visit(FunctionDefinition const& _node) override; bool visit(VariableDeclaration const& _node) override; + bool visit(ModifierDefinition const& _node) override; + bool visit(ModifierInvocation const& _node) override; + bool visit(EventDefinition const& _node) override; bool visit(TypeName const& _node) override; bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; bool visit(Mapping const& _node) override; + bool visit(ArrayTypeName const& _node) override; bool visit(InlineAssembly const& _node) override; bool visit(Block const& _node) override; + bool visit(PlaceholderStatement const& _node) override; bool visit(IfStatement const& _node) override; bool visit(WhileStatement const& _node) override; bool visit(ForStatement const& _node) override; @@ -85,18 +95,28 @@ public: bool visit(ElementaryTypeNameExpression const& _node) override; bool visit(Literal const& _node) override; + void endVisit(SourceUnit const&) override; void endVisit(ImportDirective const&) override; void endVisit(ContractDefinition const&) override; + void endVisit(InheritanceSpecifier const&) override; + void endVisit(UsingForDirective const&) override; void endVisit(StructDefinition const&) override; + void endVisit(EnumDefinition const&) override; + void endVisit(EnumValue const&) override; void endVisit(ParameterList const&) override; void endVisit(FunctionDefinition const&) override; void endVisit(VariableDeclaration const&) override; + void endVisit(ModifierDefinition const&) override; + void endVisit(ModifierInvocation const&) override; + void endVisit(EventDefinition const&) override; void endVisit(TypeName const&) override; void endVisit(ElementaryTypeName const&) override; void endVisit(UserDefinedTypeName const&) override; void endVisit(Mapping const&) override; + void endVisit(ArrayTypeName const&) override; void endVisit(InlineAssembly const&) override; void endVisit(Block const&) override; + void endVisit(PlaceholderStatement const&) override; void endVisit(IfStatement const&) override; void endVisit(WhileStatement const&) override; void endVisit(ForStatement const&) override; @@ -121,11 +141,10 @@ public: private: void process(); - void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val); void addJsonNode( ASTNode const& _node, std::string const& _nodeName, - std::initializer_list<std::pair<std::string const, std::string const>> _list, + std::initializer_list<std::pair<std::string const, Json::Value const>> _attributes, bool _hasChildren ); std::string sourceLocationToString(SourceLocation const& _location) const; diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp index bd0a020d..e16c41ab 100644 --- a/libsolidity/formal/Why3Translator.cpp +++ b/libsolidity/formal/Why3Translator.cpp @@ -466,7 +466,8 @@ bool Why3Translator::visit(BinaryOperation const& _binaryOperation) auto const& constantNumber = dynamic_cast<RationalNumberType const&>(commonType); if (constantNumber.isFractional()) error(_binaryOperation, "Fractional numbers not supported."); - add("(of_int " + toString(commonType.literalValue(nullptr)) + ")"); + else + add("(of_int " + toString(commonType.literalValue(nullptr)) + ")"); return false; } static const map<Token::Value, char const*> optrans({ @@ -488,7 +489,10 @@ bool Why3Translator::visit(BinaryOperation const& _binaryOperation) {Token::GreaterThanOrEqual, " >= "} }); if (!optrans.count(c_op)) + { error(_binaryOperation, "Operator not supported."); + return true; + } add("("); leftExpression.accept(*this); @@ -676,7 +680,8 @@ bool Why3Translator::visit(Literal const& _literal) auto const& constantNumber = dynamic_cast<RationalNumberType const&>(*type); if (constantNumber.isFractional()) error(_literal, "Fractional numbers not supported."); - add("(of_int " + toString(type->literalValue(&_literal)) + ")"); + else + add("(of_int " + toString(type->literalValue(&_literal)) + ")"); break; } default: diff --git a/scripts/travis-emscripten/publish_binary.sh b/scripts/travis-emscripten/publish_binary.sh index ac1fa95f..d202764a 100755 --- a/scripts/travis-emscripten/publish_binary.sh +++ b/scripts/travis-emscripten/publish_binary.sh @@ -60,7 +60,7 @@ fi # This file is assumed to be the product of the build_emscripten.sh script. cp ../soljson.js ./bin/"soljson-$VER-$DATE-$COMMIT.js" -./update-index.sh +node ./update cd bin LATEST=$(ls -r soljson-v* | head -n 1) cp "$LATEST" soljson-latest.js diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp index 8860727d..bb2e5663 100644 --- a/test/contracts/AuctionRegistrar.cpp +++ b/test/contracts/AuctionRegistrar.cpp @@ -24,7 +24,6 @@ #include <tuple> #include <boost/test/unit_test.hpp> #include <libdevcore/ABI.h> -#include <libdevcore/Hash.h> #include <test/libsolidity/SolidityExecutionFramework.h> using namespace std; diff --git a/test/contracts/FixedFeeRegistrar.cpp b/test/contracts/FixedFeeRegistrar.cpp index 63db0531..6d79bec6 100644 --- a/test/contracts/FixedFeeRegistrar.cpp +++ b/test/contracts/FixedFeeRegistrar.cpp @@ -32,7 +32,6 @@ #pragma warning(pop) #endif -#include <libdevcore/Hash.h> #include <test/libsolidity/SolidityExecutionFramework.h> using namespace std; diff --git a/test/contracts/Wallet.cpp b/test/contracts/Wallet.cpp index 27bdb396..7a9b0b17 100644 --- a/test/contracts/Wallet.cpp +++ b/test/contracts/Wallet.cpp @@ -32,7 +32,6 @@ #pragma warning(pop) #endif -#include <libdevcore/Hash.h> #include <test/libsolidity/SolidityExecutionFramework.h> using namespace std; diff --git a/test/libsolidity/ASTJSON.cpp b/test/libsolidity/ASTJSON.cpp index 6d914391..ec60b668 100644 --- a/test/libsolidity/ASTJSON.cpp +++ b/test/libsolidity/ASTJSON.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(smoke_test) map<string, unsigned> sourceIndices; sourceIndices["a"] = 1; Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); - BOOST_CHECK_EQUAL(astJson["name"], "root"); + BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); } BOOST_AUTO_TEST_CASE(source_location) @@ -56,12 +56,145 @@ BOOST_AUTO_TEST_CASE(source_location) map<string, unsigned> sourceIndices; sourceIndices["a"] = 1; Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); - BOOST_CHECK_EQUAL(astJson["name"], "root"); - BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "Contract"); - BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "Function"); + BOOST_CHECK_EQUAL(astJson["name"], "SourceUnit"); + BOOST_CHECK_EQUAL(astJson["children"][0]["name"], "ContractDefinition"); + BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["name"], "FunctionDefinition"); BOOST_CHECK_EQUAL(astJson["children"][0]["children"][0]["src"], "13:32:1"); } +BOOST_AUTO_TEST_CASE(inheritance_specifier) +{ + CompilerStack c; + c.addSource("a", "contract C1 {} contract C2 is C1 {}"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + BOOST_CHECK_EQUAL(astJson["children"][1]["attributes"]["name"], "C2"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["name"], "InheritanceSpecifier"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["src"], "30:2:1"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["children"][0]["name"], "UserDefinedTypeName"); + BOOST_CHECK_EQUAL(astJson["children"][1]["children"][0]["children"][0]["attributes"]["name"], "C1"); +} + +BOOST_AUTO_TEST_CASE(using_for_directive) +{ + CompilerStack c; + c.addSource("a", "library L {} contract C { using L for uint; }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value usingFor = astJson["children"][1]["children"][0]; + BOOST_CHECK_EQUAL(usingFor["name"], "UsingForDirective"); + BOOST_CHECK_EQUAL(usingFor["src"], "26:17:1"); + BOOST_CHECK_EQUAL(usingFor["children"][0]["name"], "UserDefinedTypeName"); + BOOST_CHECK_EQUAL(usingFor["children"][0]["attributes"]["name"], "L"); + BOOST_CHECK_EQUAL(usingFor["children"][1]["name"], "ElementaryTypeName"); + BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint"); +} + +BOOST_AUTO_TEST_CASE(enum_definition) +{ + CompilerStack c; + c.addSource("a", "contract C { enum E {} }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value enumDefinition = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(enumDefinition["name"], "EnumDefinition"); + BOOST_CHECK_EQUAL(enumDefinition["attributes"]["name"], "E"); + BOOST_CHECK_EQUAL(enumDefinition["src"], "13:9:1"); +} + +BOOST_AUTO_TEST_CASE(enum_value) +{ + CompilerStack c; + c.addSource("a", "contract C { enum E { A, B } }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value enumDefinition = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(enumDefinition["children"][0]["name"], "EnumValue"); + BOOST_CHECK_EQUAL(enumDefinition["children"][0]["attributes"]["name"], "A"); + BOOST_CHECK_EQUAL(enumDefinition["children"][0]["src"], "22:1:1"); + BOOST_CHECK_EQUAL(enumDefinition["children"][1]["name"], "EnumValue"); + BOOST_CHECK_EQUAL(enumDefinition["children"][1]["attributes"]["name"], "B"); + BOOST_CHECK_EQUAL(enumDefinition["children"][1]["src"], "25:1:1"); +} + +BOOST_AUTO_TEST_CASE(modifier_definition) +{ + CompilerStack c; + c.addSource("a", "contract C { modifier M(uint i) { _ } function F() M(1) {} }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value modifier = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(modifier["name"], "ModifierDefinition"); + BOOST_CHECK_EQUAL(modifier["attributes"]["name"], "M"); + BOOST_CHECK_EQUAL(modifier["src"], "13:24:1"); +} + +BOOST_AUTO_TEST_CASE(modifier_invocation) +{ + CompilerStack c; + c.addSource("a", "contract C { modifier M(uint i) { _ } function F() M(1) {} }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value modifier = astJson["children"][0]["children"][1]["children"][2]; + BOOST_CHECK_EQUAL(modifier["name"], "ModifierInvocation"); + BOOST_CHECK_EQUAL(modifier["src"], "51:4:1"); + BOOST_CHECK_EQUAL(modifier["children"][0]["attributes"]["type"], "modifier (uint256)"); + BOOST_CHECK_EQUAL(modifier["children"][0]["attributes"]["value"], "M"); + BOOST_CHECK_EQUAL(modifier["children"][1]["attributes"]["value"], "1"); +} + +BOOST_AUTO_TEST_CASE(event_definition) +{ + CompilerStack c; + c.addSource("a", "contract C { event E(); }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value event = astJson["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(event["name"], "EventDefinition"); + BOOST_CHECK_EQUAL(event["attributes"]["name"], "E"); + BOOST_CHECK_EQUAL(event["src"], "13:10:1"); +} + +BOOST_AUTO_TEST_CASE(array_type_name) +{ + CompilerStack c; + c.addSource("a", "contract C { uint[] i; }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value array = astJson["children"][0]["children"][0]["children"][0]; + BOOST_CHECK_EQUAL(array["name"], "ArrayTypeName"); + BOOST_CHECK_EQUAL(array["src"], "13:6:1"); +} + +BOOST_AUTO_TEST_CASE(placeholder_statement) +{ + CompilerStack c; + c.addSource("a", "contract C { modifier M { _ } }"); + c.parse(); + map<string, unsigned> sourceIndices; + sourceIndices["a"] = 1; + Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); + Json::Value placeholder = astJson["children"][0]["children"][0]["children"][1]["children"][0]; + BOOST_CHECK_EQUAL(placeholder["name"], "PlaceholderStatement"); + BOOST_CHECK_EQUAL(placeholder["src"], "26:1:1"); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 4e6f68b0..45f6aec5 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -25,7 +25,6 @@ #include <string> #include <tuple> #include <boost/test/unit_test.hpp> -#include <libdevcore/Hash.h> #include <libsolidity/interface/Exceptions.h> #include <test/libsolidity/SolidityExecutionFramework.h> @@ -1700,9 +1699,15 @@ BOOST_AUTO_TEST_CASE(sha256) " }\n" "}\n"; compileAndRun(sourceCode); - auto f = [&](u256 const& _input) -> u256 + auto f = [&](u256 const& _x) -> bytes { - return dev::sha256(dev::ref(toBigEndian(_input))); + if (_x == u256(4)) + return fromHex("e38990d0c7fc009880a9c07c23842e886c6bbdc964ce6bdd5817ad357335ee6f"); + if (_x == u256(5)) + return fromHex("96de8fc8c256fa1e1556d41af431cace7dca68707c78dd88c3acab8b17164c47"); + if (_x == u256(-1)) + return fromHex("af9613760f72635fbdb44a5a0a63c39f12af30f950a6ee5c971be188e89c4051"); + return fromHex(""); }; testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(5)); @@ -1717,9 +1722,15 @@ BOOST_AUTO_TEST_CASE(ripemd) " }\n" "}\n"; compileAndRun(sourceCode); - auto f = [&](u256 const& _input) -> u256 + auto f = [&](u256 const& _x) -> bytes { - return h256(dev::ripemd160(h256(_input).ref()), h256::AlignLeft); // This should be aligned right. i guess it's fixed elsewhere? + if (_x == u256(4)) + return fromHex("1b0f3c404d12075c68c938f9f60ebea4f74941a0000000000000000000000000"); + if (_x == u256(5)) + return fromHex("ee54aa84fc32d8fed5a5fe160442ae84626829d9000000000000000000000000"); + if (_x == u256(-1)) + return fromHex("1cf4e77f5966e13e109703cd8a0df7ceda7f3dc3000000000000000000000000"); + return fromHex(""); }; testSolidityAgainstCpp("a(bytes32)", f, u256(4)); testSolidityAgainstCpp("a(bytes32)", f, u256(5)); |