diff options
-rw-r--r-- | docs/contracts.rst | 101 | ||||
-rw-r--r-- | docs/control-structures.rst | 74 | ||||
-rw-r--r-- | libsolidity/interface/StandardCompiler.cpp | 4 |
3 files changed, 109 insertions, 70 deletions
diff --git a/docs/contracts.rst b/docs/contracts.rst index 470d775e..f7ceb950 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -23,12 +23,12 @@ Contracts can be created "from outside" via Ethereum transactions or from within IDEs, such as `Remix <https://remix.ethereum.org/>`_, make the creation process seamless using UI elements. Creating contracts programmatically on Ethereum is best done via using the JavaScript API `web3.js <https://github.com/ethereum/web3.js>`_. -As of today it has a method called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_ +It has a function called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_ to facilitate contract creation. When a contract is created, its constructor_ (a function declared with the ``constructor`` keyword) is executed once. -A constructor is optional. Only one constructor is allowed, and this means +A constructor is optional. Only one constructor is allowed, which means overloading is not supported. .. index:: constructor;arguments @@ -72,7 +72,7 @@ This means that cyclic creation dependencies are impossible. function changeName(bytes32 newName) public { // Only the creator can alter the name -- // the comparison is possible since contracts - // are implicitly convertible to addresses. + // are explicitly convertible to addresses. if (msg.sender == address(creator)) name = newName; } @@ -80,11 +80,11 @@ This means that cyclic creation dependencies are impossible. function transfer(address newOwner) public { // Only the current owner can transfer the token. if (msg.sender != owner) return; + // We also want to ask the creator if the transfer // is fine. Note that this calls a function of the // contract defined below. If the call fails (e.g. - // due to out-of-gas), the execution here stops - // immediately. + // due to out-of-gas), the execution also fails here. if (creator.isTokenTransferOK(owner, newOwner)) owner = newOwner; } @@ -102,7 +102,7 @@ This means that cyclic creation dependencies are impossible. return new OwnedToken(name); } - function changeName(OwnedToken tokenAddress, bytes32 name) public { + function changeName(OwnedToken tokenAddress, bytes32 name) public { // Again, the external type of `tokenAddress` is // simply `address`. tokenAddress.changeName(name); @@ -162,7 +162,7 @@ For state variables, ``external`` is not possible. .. note:: Everything that is inside a contract is visible to - all external observers. Making something ``private`` + all observers external to the blockchain. Making something ``private`` only prevents other contracts from accessing and modifying the information, but it will still be visible to the whole world outside of the blockchain. @@ -246,8 +246,8 @@ when they are declared. The getter functions have external visibility. If the symbol is accessed internally (i.e. without ``this.``), -it is evaluated as a state variable. If it is accessed externally -(i.e. with ``this.``), it is evaluated as a function. +it evaluates to a state variable. If it is accessed externally +(i.e. with ``this.``), it evaluates to a function. :: @@ -261,7 +261,7 @@ it is evaluated as a state variable. If it is accessed externally } } -If you have a `public` state variable of array type, then you can only retrieve +If you have a ``public`` state variable of array type, then you can only retrieve single elements of the array via the generated getter function. This mechanism exists to avoid high gas costs when returning an entire array. You can use arguments to specify which individual element to return, for example @@ -438,7 +438,7 @@ State variables can be declared as ``constant``. In this case, they have to be assigned from an expression which is a constant at compile time. Any expression that accesses storage, blockchain data (e.g. ``now``, ``address(this).balance`` or ``block.number``) or -execution data (``msg.value`` or ``gasleft()``) or make calls to external contracts are disallowed. Expressions +execution data (``msg.value`` or ``gasleft()``) or makes calls to external contracts is disallowed. Expressions that might have a side-effect on memory allocation are allowed, but those that might have a side-effect on other memory objects are not. The built-in functions ``keccak256``, ``sha256``, ``ripemd160``, ``ecrecover``, ``addmod`` and ``mulmod`` @@ -483,7 +483,8 @@ Functions can be declared ``view`` in which case they promise not to modify the .. note:: If the compiler's EVM target is Byzantium or newer (default) the opcode - ``STATICCALL`` is used. + ``STATICCALL`` is used for ``view`` functions which enforces the state + to stay unmodified as part of the EVM execution. The following statements are considered modifying the state: @@ -510,7 +511,7 @@ The following statements are considered modifying the state: ``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0. .. note:: - Getter methods are marked ``view``. + Getter methods are automatically marked ``view``. .. note:: Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode @@ -530,7 +531,8 @@ Pure Functions Functions can be declared ``pure`` in which case they promise not to read from or modify the state. .. note:: - If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used. + If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used, + which does not guarantee that the state is not read, but at least that it is not modified. In addition to the list of state modifying statements explained above, the following are considered reading from the state: @@ -562,7 +564,6 @@ In addition to the list of state modifying statements explained above, the follo It is not possible to prevent functions from reading the state at the level of the EVM, it is only possible to prevent them from writing to the state (i.e. only ``view`` can be enforced at the EVM level, ``pure`` can not). - It is a non-circumventable runtime checks done by the EVM. .. warning:: Before version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state. @@ -571,8 +572,8 @@ In addition to the list of state modifying statements explained above, the follo not do state-changing operations, but it cannot check that the contract that will be called at runtime is actually of that type. -.. warning:: - Before version 0.5.0 the compiler did not enforce that ``view`` is not writing the state. +.. note:: + Before version 0.5.0 the compiler did not enforce that ``pure`` is not reading the state. .. index:: ! fallback function, function;fallback @@ -609,6 +610,12 @@ Like any function, the fallback function can execute complex operations as long any payload supplied with the call. .. warning:: + The fallback function is also executed if the caller meant to call + a function that is not available. If you want to implement the fallback + function only to receive ether, you should add a check + like ``require(msg.data.length == 0)`` to prevent invalid calls. + +.. warning:: Contracts that receive Ether directly (without a function call, i.e. using ``send`` or ``transfer``) but do not define a fallback function throw an exception, sending back the Ether (this was different @@ -765,9 +772,9 @@ Frontier and Homestead, but this might change with Serenity). Log and event data is not accessible from within contracts (not even from the contract that created them). -SPV proofs for logs are possible, so if an external entity supplies +"Simple payment verification" (SPV) proofs for logs are possible, so if an external entity supplies a contract with such a proof, it can check that the log actually -exists inside the blockchain. But be aware that block headers have to be supplied because +exists inside the blockchain. Be aware that block headers have to be supplied because the contract can only see the last 256 block hashes. Up to three parameters can @@ -1043,10 +1050,8 @@ initialisation code. Before the constructor code is executed, state variables are initialised to their specified value if you initialise them inline, or zero if you do not. -After the final code of the contract is returned. The final deployment of -the code costs additional gas linear to the length of the code. If you did not -supply enough gas to initiate the state variables declared in the constructor, -then an "out of gas" exception is generated. +After the constructor has run, the final code of the contract is returned. The deployment of +the code costs additional gas linear to the length of the code. Constructor functions can be either ``public`` or ``internal``. If there is no constructor, the contract will assume the default constructor, which is @@ -1071,7 +1076,8 @@ equivalent to ``constructor() public {}``. For example: A constructor set as ``internal`` causes the contract to be marked as :ref:`abstract <abstract-contract>`. .. warning :: - Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. This syntax was deprecated and is not allowed anymore in version 0.5.0. + Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. + This syntax was deprecated and is not allowed anymore in version 0.5.0. .. index:: ! base;constructor @@ -1101,7 +1107,7 @@ derived contracts need to specify all of them. This can be done in two ways:: } One way is directly in the inheritance list (``is Base(7)``). The other is in -the way a modifier would be invoked as part of the header of +the way a modifier is invoked as part of the derived constructor (``Base(_y * _y)``). The first way to do it is more convenient if the constructor argument is a constant and defines the behaviour of the contract or @@ -1111,7 +1117,7 @@ derived contract. Arguments have to be given either in the inheritance list or in modifier-style in the derived constructor. Specifying arguments in both places is an error. -If a derived contract doesn't specify the arguments to all of its base +If a derived contract does not specify the arguments to all of its base contracts' constructors, it will be abstract. .. index:: ! inheritance;multiple, ! linearization, ! C3 linearization @@ -1124,7 +1130,7 @@ Multiple Inheritance and Linearization Languages that allow multiple inheritance have to deal with several problems. One is the `Diamond Problem <https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem>`_. Solidity is similar to Python in that it uses "`C3 Linearization <https://en.wikipedia.org/wiki/C3_linearization>`_" -to force a specific order in the DAG of base classes. This +to force a specific order in the directed acyclic graph of base classes. This results in the desirable property of monotonicity but disallows some inheritance graphs. Especially, the order in which the base classes are given in the ``is`` directive is @@ -1218,16 +1224,15 @@ Interfaces Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions: -- Cannot inherit other contracts or interfaces. +- They cannot inherit other contracts or interfaces. - All declared functions must be external. -- Cannot define constructor. -- Cannot define variables. -- Cannot define structs. +- They cannot declare a constructor. +- They cannot declare state variables. Some of these restrictions might be lifted in the future. Interfaces are basically limited to what the Contract ABI can represent, and the conversion between the ABI and -an Interface should be possible without any information loss. +an interface should be possible without any information loss. Interfaces are denoted by their own keyword: @@ -1236,18 +1241,23 @@ Interfaces are denoted by their own keyword: pragma solidity ^0.4.11; interface Token { + enum TokenType { Fungible, NonFungible } + struct Coin { string obverse; string reverse; } function transfer(address recipient, uint amount) external; } Contracts can inherit interfaces as they would inherit other contracts. +Types defined inside interfaces and other contract-like structures +can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``. + .. index:: ! library, callcode, delegatecall .. _libraries: -************ +********* Libraries -************ +********* Libraries are similar to contracts, but their purpose is that they are deployed only once at a specific address and their code is reused using the ``DELEGATECALL`` @@ -1261,7 +1271,14 @@ would have no way to name them, otherwise). Library functions can only be called directly (i.e. without the use of ``DELEGATECALL``) if they do not modify the state (i.e. if they are ``view`` or ``pure`` functions), because libraries are assumed to be stateless. In particular, it is -not possible to destroy a library unless Solidity's type system is circumvented. +not possible to destroy a library. + +.. note:: + Until version 0.4.20, it was possible to destroy libraries by + circumventing Solidity's type system. Starting from that version, + libraries contain a :ref:`mechanism<call-protection>` that + disallows state-modifying functions + to be called directly (i.e. without ``DELEGATECALL``). Libraries can be seen as implicit base contracts of the contracts that use them. They will not be explicitly visible in the inheritance hierarchy, but calls @@ -1277,7 +1294,7 @@ contract, and a regular ``JUMP`` call will be used instead of a ``DELEGATECALL`` .. index:: using for, set -The following example illustrates how to use libraries (but +The following example illustrates how to use libraries (butmanual method be sure to check out :ref:`using for <using-for>` for a more advanced example to implement a set). @@ -1345,7 +1362,7 @@ parameters and in any position. The calls to ``Set.contains``, ``Set.insert`` and ``Set.remove`` are all compiled as calls (``DELEGATECALL``) to an external -contract/library. If you use libraries, take care that an +contract/library. If you use libraries, be aware that an actual external function call is performed. ``msg.sender``, ``msg.value`` and ``this`` will retain their values in this call, though (prior to Homestead, because of the use of ``CALLCODE``, ``msg.sender`` and @@ -1423,6 +1440,14 @@ will contain placeholders of the form ``__Set______`` (where manually by replacing all those 40 symbols by the hex encoding of the address of the library contract. +.. note:: + Manually linking libraries on the generated bytecode is discouraged, because + it is restricted to 36 characters. + You should ask the compiler to link the libraries at the time + a contract is compiled by either using + the ``--libraries`` option of ``solc`` or the ``libraries`` key if you use + the standard-JSON interface to the compiler. + Restrictions for libraries in comparison to contracts: - No state variables @@ -1431,6 +1456,8 @@ Restrictions for libraries in comparison to contracts: (These might be lifted at a later point.) +.. _call-protection: + Call Protection For Libraries ============================= diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 7c91cab7..ae0abc49 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -14,8 +14,8 @@ parameters as output. Input Parameters ---------------- -The input parameters are declared the same way as variables are. As an -exception, unused parameters can omit the variable name. +The input parameters are declared the same way as variables are. +The name of unused parameters can be omitted. For example, suppose we want our contract to accept one kind of external calls with two integers, we would write something like:: @@ -29,6 +29,9 @@ something like:: } } +Input parameters can be used just as any other local variable +can be used, they can also be assigned to. + Output Parameters ----------------- @@ -51,24 +54,20 @@ write:: } The names of output parameters can be omitted. -The output values can also be specified using ``return`` statements. -The ``return`` statements are also capable of returning multiple -values, see :ref:`multi-return`. -Return parameters are initialized to zero; if they are not explicitly -set, they stay to be zero. - -Input parameters and output parameters can be used as expressions in -the function body. There, they are also usable in the left-hand side -of assignment. +The output values can also be specified using ``return`` statements, +which are also capable of :ref:`returning multiple values<multi-return>`. +Return parameters can be used as any other local variable and they +are zero-initialized; if they are not explicitly +set, they stay zero. .. index:: if, else, while, do/while, for, break, continue, return, switch, goto Control Structures =================== -Most of the control structures from JavaScript are available in Solidity -except for ``switch`` and ``goto``. So -there is: ``if``, ``else``, ``while``, ``do``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with +Most of the control structures known from curly-braces languages are available in Solidity: + +There is: ``if``, ``else``, ``while``, ``do``, ``for``, ``break``, ``continue``, ``return``, with the usual semantics known from C or JavaScript. Parentheses can *not* be omitted for conditionals, but curly brances can be omitted @@ -112,6 +111,9 @@ the effect that the current memory is not cleared, i.e. passing memory reference to internally-called functions is very efficient. Only functions of the same contract can be called internally. +You should still avoid excessive recursion, as every internal function call +uses up at least one stack slot and there are at most 1024 slots available. + External Function Calls ----------------------- @@ -143,7 +145,7 @@ You need to use the modifier ``payable`` with the ``info`` function because otherwise, the ``.value()`` option would not be available. .. warning:: - Be careful that ``feed.info.value(10).gas(800)`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the parentheses at the end perform the actual call. + Be careful that ``feed.info.value(10).gas(800)`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the parentheses at the end perform the actual call. So in this case, the function is not called. Function calls cause exceptions if the called contract does not exist (in the sense that the account does not contain code) or if the called contract itself @@ -167,7 +169,7 @@ throws an exception or goes out of gas. Named Calls and Anonymous Function Parameters --------------------------------------------- -Function call arguments can also be given by name, in any order, +Function call arguments can be given by name, in any order, if they are enclosed in ``{ }`` as can be seen in the following example. The argument list has to coincide by name with the list of parameters from the function declaration, but can be in arbitrary order. @@ -214,9 +216,9 @@ Those parameters will still be present on the stack, but they are inaccessible. Creating Contracts via ``new`` ============================== -A contract can create a new contract using the ``new`` keyword. The full -code of the contract being created has to be known in advance, so recursive -creation-dependencies are not possible. +A contract can create other contracts using the ``new`` keyword. The full +code of the contract being created has to be known when the creating contract +is compiled so recursive creation-dependencies are not possible. :: @@ -244,7 +246,7 @@ creation-dependencies are not possible. } } -As seen in the example, it is possible to forward Ether while creating +As seen in the example, it is possible to send Ether while creating an instance of ``D`` using the ``.value()`` option, but it is not possible to limit the amount of gas. If the creation fails (due to out-of-stack, not enough balance or other problems), @@ -269,8 +271,11 @@ Assignment Destructuring Assignments and Returning Multiple Values ------------------------------------------------------- -Solidity internally allows tuple types, i.e. a list of objects of potentially different types whose size is a constant at compile-time. Those tuples can be used to return multiple values at the same time. -These can then either be assigned to newly declared variables or to pre-existing variables (or LValues in general): +Solidity internally allows tuple types, i.e. a list of objects of potentially different types whose number is a constant at compile-time. Those tuples can be used to return multiple values at the same time. +These can then either be assigned to newly declared variables or to pre-existing variables (or LValues in general). + +Tuples are not proper types in Solidity, they can only be used to form syntactic +groupings of expressions. :: @@ -294,15 +299,23 @@ These can then either be assigned to newly declared variables or to pre-existing } } +It is not possible to mix variable declarations and non-declaration assignments, +i.e. the following is not valid: ``(x, uint y) = (1, 2);`` + .. note:: Prior to version 0.5.0 it was possible to assign to tuples of smaller size, either filling up on the left or on the right side (which ever was empty). This is now disallowed, so both sides have to have the same number of components. +.. warning:: + Be careful when assigning to multiple variables at the same time when + reference types are involved, because it could lead to unexpected + copying behaviour. + Complications for Arrays and Structs ------------------------------------ -The semantics of assignment are a bit more complicated for non-value types like arrays and structs. +The semantics of assignments are a bit more complicated for non-value types like arrays and structs. Assigning *to* a state variable always creates an independent copy. On the other hand, assigning to a local variable creates an independent copy only for elementary types, i.e. static types that fit into 32 bytes. If structs or arrays (including ``bytes`` and ``string``) are assigned from a state variable to a local variable, the local variable holds a reference to the original state variable. A second assignment to the local variable does not modify the state but only changes the reference. Assignments to members (or elements) of the local variable *do* change the state. .. index:: ! scoping, declarations, default value @@ -320,11 +333,11 @@ and ``string``, the default value is an empty array or string. Scoping in Solidity follows the widespread scoping rules of C99 (and many other languages): Variables are visible from the point right after their declaration -until the end of a ``{ }``-block. As an exception to this rule, variables declared in the +until the end of the smallest ``{ }``-block that contains the declaration. As an exception to this rule, variables declared in the initialization part of a for-loop are only visible until the end of the for-loop. Variables and other items declared outside of a code block, for example functions, contracts, -user-defined types, etc., do not change their scoping behaviour. This means you can +user-defined types, etc., are visible even before they were declared. This means you can use state variables before they are declared and call functions recursively. As a consequence, the following examples will compile without warnings, since @@ -368,7 +381,7 @@ In any case, you will get a warning about the outer variable being shadowed. .. warning:: Before version 0.5.0 Solidity followed the same scoping rules as JavaScript, that is, a variable declared anywhere within a function would be in scope - for the entire function, regardless where it was declared. Note that this is a breaking change. The following example shows a code snippet that used + for the entire function, regardless where it was declared. The following example shows a code snippet that used to compile but leads to an error starting from version 0.5.0. :: @@ -400,17 +413,17 @@ If used properly, analysis tools can evaluate your contract to identify the cond There are two other ways to trigger exceptions: The ``revert`` function can be used to flag an error and revert the current call. It is possible to provide a string message containing details about the error that will be passed back to the caller. -The deprecated keyword ``throw`` can also be used as an alternative to ``revert()`` (but only without error message). .. note:: - From version 0.4.13 the ``throw`` keyword is deprecated and will be phased out in the future. + There used to be a keyword called ``throw`` with the same semantics as ``revert()`` which + whas deprecated in version 0.4.13 and removed in version 0.5.0. When exceptions happen in a sub-call, they "bubble up" (i.e. exceptions are rethrown) automatically. Exceptions to this rule are ``send`` -and the low-level functions ``call``, ``delegatecall``, ``callcode`` and ``staticcall`` -- those return ``false`` in case +and the low-level functions ``call``, ``delegatecall`` and ``staticcall`` -- those return ``false`` as their first return value in case of an exception instead of "bubbling up". .. warning:: - The low-level ``call``, ``delegatecall``, ``callcode`` and ``staticcall`` will return success if the called account is non-existent, as part of the design of EVM. Existence must be checked prior to calling if desired. + The low-level functions ``call``, ``delegatecall`` and ``staticcall`` return ``true`` as their first return value if the called account is non-existent, as part of the design of EVM. Existence must be checked prior to calling if desired. Catching exceptions is not yet possible. @@ -447,7 +460,6 @@ An ``assert``-style exception is generated in the following situations: A ``require``-style exception is generated in the following situations: -#. Calling ``throw``. #. Calling ``require`` with an argument that evaluates to ``false``. #. If you call a function via a message call but it does not finish properly (i.e. it runs out of gas, has no matching function, or throws an exception itself), except when a low level operation ``call``, ``send``, ``delegatecall``, ``callcode`` or ``staticcall`` is used. The low level operations never throw exceptions but indicate failures by returning ``false``. #. If you create a contract using the ``new`` keyword but the contract creation does not finish properly (see above for the definition of "not finish properly"). diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index b53c5a5e..e7b1553f 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -615,7 +615,7 @@ string StandardCompiler::compile(string const& _input) noexcept } catch (...) { - return "{\"errors\":\"[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error parsing input JSON.\"}]}"; + return "{\"errors\":[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error parsing input JSON.\"}]}"; } // cout << "Input: " << input.toStyledString() << endl; @@ -628,6 +628,6 @@ string StandardCompiler::compile(string const& _input) noexcept } catch (...) { - return "{\"errors\":\"[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error writing output JSON.\"}]}"; + return "{\"errors\":[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error writing output JSON.\"}]}"; } } |