diff options
author | chriseth <chris@ethereum.org> | 2018-12-03 22:48:03 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-03 22:48:03 +0800 |
commit | c8a2cb62832afb2dc09ccee6fd42c1516dfdb981 (patch) | |
tree | 7977e9dcbbc215088c05b847f849871ef5d4ae66 /docs | |
parent | 1d4f565a64988a3400847d2655ca24f73f234bc6 (diff) | |
parent | 590be1d84cea9850ce69b68be3dc5294b39041e5 (diff) | |
download | dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.gz dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.bz2 dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.lz dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.xz dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.zst dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.zip |
Merge pull request #5571 from ethereum/develop
Version 0.5.1
Diffstat (limited to 'docs')
-rw-r--r-- | docs/bugs_by_version.json | 4 | ||||
-rw-r--r-- | docs/contracts.rst | 134 | ||||
-rw-r--r-- | docs/contributing.rst | 81 | ||||
-rw-r--r-- | docs/control-structures.rst | 81 | ||||
-rw-r--r-- | docs/frequently-asked-questions.rst | 145 | ||||
-rw-r--r-- | docs/grammar.txt | 35 | ||||
-rw-r--r-- | docs/index.rst | 64 | ||||
-rw-r--r-- | docs/installing-solidity.rst | 2 | ||||
-rw-r--r-- | docs/introduction-to-smart-contracts.rst | 2 | ||||
-rw-r--r-- | docs/layout-of-source-files.rst | 2 | ||||
-rw-r--r-- | docs/lll.rst | 7 | ||||
-rw-r--r-- | docs/miscellaneous.rst | 6 | ||||
-rw-r--r-- | docs/resources.rst | 6 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 187 | ||||
-rw-r--r-- | docs/structure-of-a-contract.rst | 3 | ||||
-rw-r--r-- | docs/style-guide.rst | 18 | ||||
-rw-r--r-- | docs/types.rst | 54 | ||||
-rw-r--r-- | docs/units-and-global-variables.rst | 7 | ||||
-rw-r--r-- | docs/yul.rst | 52 |
19 files changed, 419 insertions, 471 deletions
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 2631b286..658aab9c 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -612,5 +612,9 @@ "0.5.0": { "bugs": [], "released": "2018-11-13" + }, + "0.5.1": { + "bugs": [], + "released": "2018-12-03" } }
\ No newline at end of file diff --git a/docs/contracts.rst b/docs/contracts.rst index c1c51e56..98419430 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -485,6 +485,110 @@ value types and strings. Functions ********* +.. _function-parameters-return-variables: + +Function Parameters and Return Variables +======================================== + +As in JavaScript, functions may take parameters as input. Unlike in JavaScript +and C, functions may also return an arbitrary number of values as output. + +Function Parameters +------------------- + +Function parameters are declared the same way as variables, and the name of +unused parameters can be omitted. + +For example, if you want your contract to accept one kind of external call +with two integers, you would use something like:: + + pragma solidity >=0.4.16 <0.6.0; + + contract Simple { + uint sum; + function taker(uint _a, uint _b) public { + sum = _a + _b; + } + } + +Function parameters can be used as any other local variable and they can also be assigned to. + +.. note:: + + An :ref:`external function<external-function-calls>` cannot accept a + multi-dimensional array as an input + parameter. This functionality is possible if you enable the new + experimental ``ABIEncoderV2`` feature by adding ``pragma experimental ABIEncoderV2;`` to your source file. + + An :ref:`internal function<external-function-calls>` can accept a + multi-dimensional array without enabling the feature. + +.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct + +Return Variables +---------------- + +Function return variables are declared with the same syntax after the +``returns`` keyword. + +For example, suppose you want to return two results: the sum and the product of +two integers passed as function parameters, then you use something like:: + + pragma solidity >=0.4.16 <0.6.0; + + contract Simple { + function arithmetic(uint _a, uint _b) + public + pure + returns (uint o_sum, uint o_product) + { + o_sum = _a + _b; + o_product = _a * _b; + } + } + +The names of return variables can be omitted. +Return variables can be used as any other local variable and they +are initialized with their :ref:`default value <default-value>` and have that value unless explicitly set. + +You can either explicitly assign to return variables and +then leave the function using ``return;``, +or you can provide return values +(either a single or :ref:`multiple ones<multi-return>`) directly with the ``return`` +statement:: + + pragma solidity >=0.4.16 <0.6.0; + + contract Simple { + function arithmetic(uint _a, uint _b) + public + pure + returns (uint o_sum, uint o_product) + { + return (_a + _b, _a * _b); + } + } + +This form is equivalent to first assigning values to the +return variables and then using ``return;`` to leave the function. + +.. note:: + You cannot return some types from non-internal functions, notably + multi-dimensional dynamic arrays and structs. If you enable the + new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental + ABIEncoderV2;`` to your source file then more types are available, but + ``mapping`` types are still limited to inside a single contract and you + cannot transfer them. + +.. _multi-return: + +Returning Multiple Values +------------------------- + +When a function has multiple return types, the statement ``return (v0, v1, ..., vn) can be used to return multiple values. +vn)`` can return multiple values. The number of components must be +the same as the number of return types. + .. index:: ! view function, function;view .. _view-functions: @@ -569,6 +673,20 @@ In addition to the list of state modifying statements explained above, the follo } } +Pure functions are able to use the `revert()` and `require()` functions to revert +potential state changes when an :ref:`error occurs <assert-and-require>`. + +Reverting a state change is not considered a "state modification", as only changes to the +state made previously in code that did not have the ``view`` or ``pure`` restriction +are reverted and that code has the option to catch the ``revert`` and not pass it on. + +This behaviour is also in line with the ``STATICCALL`` opcode. + +.. warning:: + 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). + .. note:: Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode for ``pure`` functions. @@ -577,13 +695,8 @@ In addition to the list of state modifying statements explained above, the follo By using ``STATICCALL`` for ``pure`` functions, modifications to the state are prevented on the level of the EVM. -.. warning:: - 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). - -.. warning:: - Before version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state. +.. note:: + Prior to version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state. It is a compile-time type check, which can be circumvented doing invalid explicit conversions between contract types, because the compiler can verify that the type of the contract does not do state-changing operations, but it cannot check that the contract that will be called @@ -932,14 +1045,15 @@ Additional Resources for Understanding Events Inheritance *********** -Solidity supports multiple inheritance by copying code including polymorphism. +Solidity supports multiple inheritance including polymorphism. All function calls are virtual, which means that the most derived function -is called, except when the contract name is explicitly given. +is called, except when the contract name is explicitly given or the +``super`` keyword is used. When a contract inherits from other contracts, only a single contract is created on the blockchain, and the code from all the base contracts -is copied into the created contract. +is compiled into the created contract. The general inheritance system is very similar to `Python's <https://docs.python.org/3/tutorial/classes.html#inheritance>`_, diff --git a/docs/contributing.rst b/docs/contributing.rst index 11f95206..43b2fd38 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -70,16 +70,15 @@ Thank you for your help! Running the compiler tests ========================== -There is a script at ``scripts/tests.sh`` which executes most of the tests and +The ``./scripts/tests.sh`` script executes most Solidity tests and runs ``aleth`` automatically if it is in the path, but does not download it, -so it most likely will not work right away. Please read on for the details. +so you need to install it first. Please read on for the details. -Solidity includes different types of tests. Most of them are bundled in the application -called ``soltest``. Some of them require the ``aleth`` client in testing mode, -some others require ``libz3`` to be installed. +Solidity includes different types of tests, most of them bundled into the ``soltest`` +application. Some of them require the ``aleth`` client in testing mode, others require ``libz3``. -To run a basic set of tests that neither require ``aleth`` nor ``libz3``, run -``./scripts/soltest.sh --no-ipc --no-smt``. This script will run ``build/test/soltest`` +To run a basic set of tests that require neither ``aleth`` nor ``libz3``, run +``./scripts/soltest.sh --no-ipc --no-smt``. This script runs ``./build/test/soltest`` internally. .. note :: @@ -90,23 +89,41 @@ internally. The option ``--no-smt`` disables the tests that require ``libz3`` and ``--no-ipc`` disables those that require ``aleth``. -If you want to run the ipc tests (those test the semantics of the generated code), +If you want to run the ipc tests (that test the semantics of the generated code), you need to install `aleth <https://github.com/ethereum/cpp-ethereum/releases/download/solidityTester/aleth_2018-06-20_artful>`_ and run it in testing mode: ``aleth --test -d /tmp/testeth`` (make sure to rename it). -Then you run the actual tests: ``./scripts/soltest.sh --ipcpath /tmp/testeth/geth.ipc``. +To run the actual tests, use: ``./scripts/soltest.sh --ipcpath /tmp/testeth/geth.ipc``. -To run a subset of tests, filters can be used: +To run a subset of tests, you can use filters: ``./scripts/soltest.sh -t TestSuite/TestName --ipcpath /tmp/testeth/geth.ipc``, where ``TestName`` can be a wildcard ``*``. -The script ``scripts/tests.sh`` also runs commandline tests and compilation tests +For example, here's an example test you might run; +``./scripts/soltest.sh -t "yulOptimizerTests/disambiguator/*" --no-ipc --no-smt``. +This will test all the tests for the disambiguator. + +To get a list of all tests, use +``./build/test/soltest --list_content=HRF -- --ipcpath /tmp/irrelevant``. + +If you want to debug using GDB, make sure you build differently than the "usual". +For example, you could run the following command in your ``build`` folder: +:: + + cmake -DCMAKE_BUILD_TYPE=Debug .. + make + +This will create symbols such that when you debug a test using the ``--debug`` flag, you will have acecess to functions and varialbes in which you can break or print with. + + +The script ``./scripts/tests.sh`` also runs commandline tests and compilation tests in addition to those found in ``soltest``. -The CI even runs some additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target. +The CI runs additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target. .. note :: - Some versions of ``aleth`` cannot be used for testing. We suggest using the same version that is used by the Solidity continuous integration tests. + You can not use some versions of ``aleth`` for testing. We suggest using + the same version that the Solidity continuous integration tests use. Currently the CI uses ``d661ac4fec0aeffbedcdc195f67f5ded0c798278`` of ``aleth``. Writing and running syntax tests @@ -114,11 +131,11 @@ Writing and running syntax tests Syntax tests check that the compiler generates the correct error messages for invalid code and properly accepts valid code. -They are stored in individual files inside ``tests/libsolidity/syntaxTests``. +They are stored in individual files inside the ``tests/libsolidity/syntaxTests`` folder. These files must contain annotations, stating the expected result(s) of the respective test. -The test suite will compile and check them against the given expectations. +The test suite compiles and checks them against the given expectations. -Example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol`` +For example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol`` :: @@ -129,14 +146,14 @@ Example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol`` // ---- // DeclarationError: (36-52): Identifier already declared. -A syntax test must contain at least the contract under test itself, followed by the separator ``// ----``. The following comments are used to describe the +A syntax test must contain at least the contract under test itself, followed by the separator ``// ----``. The comments that follow the separator are used to describe the expected compiler errors or warnings. The number range denotes the location in the source where the error occurred. -In case the contract should compile without any errors or warning, the section after the separator has to be empty -and the separator can be left out completely. +If you want the contract to compile without any errors or warning you can leave +out the separator and the comments that follow it. -In the above example, the state variable ``variable`` was declared twice, which is not allowed. This will result in a ``DeclarationError`` stating that the identifier was already declared. +In the above example, the state variable ``variable`` was declared twice, which is not allowed. This results in a ``DeclarationError`` stating that the identifier was already declared. -The tool that is being used for those tests is called ``isoltest`` and can be found under ``./test/tools/``. It is an interactive tool which allows +The ``isoltest`` tool is used for these tests and you can find it under ``./build/test/tools/``. It is an interactive tool which allows editing of failing contracts using your preferred text editor. Let's try to break this test by removing the second declaration of ``variable``: :: @@ -147,7 +164,7 @@ editing of failing contracts using your preferred text editor. Let's try to brea // ---- // DeclarationError: (36-52): Identifier already declared. -Running ``./test/isoltest`` again will result in a test failure: +Running ``./build/test/isoltest`` again results in a test failure: :: @@ -163,15 +180,19 @@ Running ``./test/isoltest`` again will result in a test failure: Success -``isoltest`` prints the expected result next to the obtained result, but also provides a way to change edit / update / skip the current contract or to even quit. +``isoltest`` prints the expected result next to the obtained result, and also +provides a way to edit, update or skip the current contract file, or quit the application. + It offers several options for failing tests: -- edit: ``isoltest`` tries to open the contract in an editor so you can adjust it. It either uses the editor given on the command line (as ``isoltest --editor /path/to/editor``), in the environment variable ``EDITOR`` or just ``/usr/bin/editor`` (in this order). -- update: Updates the contract under test. This either removes the annotation which contains the exception not met or adds missing expectations. The test will then be run again. -- skip: Skips the execution of this particular test. -- quit: Quits ``isoltest``. +- ``edit``: ``isoltest`` tries to open the contract in an editor so you can adjust it. It either uses the editor given on the command line (as ``isoltest --editor /path/to/editor``), in the environment variable ``EDITOR`` or just ``/usr/bin/editor`` (in that order). +- ``update``: Updates the expectations for contract under test. This updates the annotations by removing unmet expectations and adding missing expectations. The test is then run again. +- ``skip``: Skips the execution of this particular test. +- ``quit``: Quits ``isoltest``. + +All of these options apply to the current contract, expect ``quit`` which stops the entire testing process. -Automatically updating the test above will change it to +Automatically updating the test above changes it to :: @@ -180,7 +201,7 @@ Automatically updating the test above will change it to } // ---- -and re-run the test. It will now pass again: +and re-run the test. It now passes again: :: @@ -190,7 +211,7 @@ and re-run the test. It will now pass again: .. note:: - Please choose a name for the contract file that explains what it tests, e.g. ``double_variable_declaration.sol``. + Choose a name for the contract file that explains what it tests, e.g. ``double_variable_declaration.sol``. Do not put more than one contract into a single file, unless you are testing inheritance or cross-contract calls. Each file should test one aspect of your new feature. diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 5e3b722b..f8016806 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -2,74 +2,8 @@ Expressions and Control Structures ################################## -.. index:: ! parameter, parameter;input, parameter;output, parameter;multiple +.. index:: ! parameter, parameter;input, parameter;output, function parameter, parameter;function, return variable, variable;return, return -Input Parameters and Output Parameters -====================================== - -As in Javascript, functions may take parameters as input; -unlike in Javascript and C, they may also return arbitrary number of -parameters as output. - -Input Parameters ----------------- - -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:: - - pragma solidity >=0.4.16 <0.6.0; - - contract Simple { - uint sum; - function taker(uint _a, uint _b) public { - sum = _a + _b; - } - } - -Input parameters can be used just as any other local variable -can be used, they can also be assigned to. - -.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct - -Output Parameters ------------------ - -The output parameters can be declared with the same syntax after the -``returns`` keyword. For example, suppose we wished to return two results: -the sum and the product of the two given integers, then we would -write:: - - pragma solidity >=0.4.16 <0.6.0; - - contract Simple { - function arithmetic(uint _a, uint _b) - public - pure - returns (uint o_sum, uint o_product) - { - o_sum = _a + _b; - o_product = _a * _b; - } - } - -The names of output parameters can be omitted. -The return values can 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. - - -.. note:: - You cannot return some types from non-internal functions, notably - multi-dimensional dynamic arrays and structs. If you enable the - new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental - ABIEncoderV2;`` to your source file then more types are available, but - ``mapping`` types are still limited to inside a single contract and you - cannot transfer them. .. index:: if, else, while, do/while, for, break, continue, return, switch, goto @@ -88,15 +22,6 @@ Note that there is no type conversion from non-boolean to boolean types as there is in C and JavaScript, so ``if (1) { ... }`` is *not* valid Solidity. -.. _multi-return: - -Returning Multiple Values -------------------------- - -When a function has multiple output parameters, ``return (v0, v1, ..., -vn)`` can return multiple values. The number of components must be -the same as the number of output parameters. - .. index:: ! function;call, function;internal, function;external .. _function-calls: @@ -104,6 +29,8 @@ the same as the number of output parameters. Function Calls ============== +.. _internal-function-calls: + Internal Function Calls ----------------------- @@ -125,6 +52,8 @@ 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: + External Function Calls ----------------------- diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 8b655b0d..f3c5b1f7 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -38,24 +38,6 @@ has it (which includes `Remix <https://remix.ethereum.org/>`_), then ``contractname.kill.sendTransaction({from:eth.coinbase})``, just the same as my examples. -Is it possible to in-line initialize an array like so: ``string[] myarray = ["a", "b"];`` -========================================================================================= - -Yes. However it should be noted that this currently only works with statically sized memory arrays. You can even create an inline memory -array in the return statement. - -Example:: - - pragma solidity >=0.4.16 <0.6.0; - - contract C { - function f() public pure returns (uint8[5] memory) { - string[4] memory adaArr = ["This", "is", "an", "array"]; - adaArr[0] = "That"; - return [1, 2, 3, 4, 5]; - } - } - If I return an ``enum``, I only get integer values in web3.js. How to get the named values? =========================================================================================== @@ -143,44 +125,6 @@ arguments for you. See `ping.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/45_ping.sol>`_ and `pong.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/45_pong.sol>`_. -When returning a value of say ``uint`` type, is it possible to return an ``undefined`` or "null"-like value? -============================================================================================================ - -This is not possible, because all types use up the full value range. - -You have the option to ``throw`` on error, which will also revert the whole -transaction, which might be a good idea if you ran into an unexpected -situation. - -If you do not want to throw, you can return a pair:: - - pragma solidity >0.4.23 <0.6.0; - - contract C { - uint[] counters; - - function getCounter(uint index) - public - view - returns (uint counter, bool error) { - if (index >= counters.length) - return (0, true); - else - return (counters[index], false); - } - - function checkCounter(uint index) public view { - (uint counter, bool error) = getCounter(index); - if (error) { - // Handle the error - } else { - // Do something with counter. - require(counter > 7, "Invalid counter value"); - } - } - } - - Are comments included with deployed contracts and do they increase deployment gas? ================================================================================== @@ -232,24 +176,6 @@ Note2: Optimizing storage access can pull the gas costs down considerably, becau currently do not work across loops and also have a problem with bounds checking. You might get much better results in the future, though. -What happens to a ``struct``'s mapping when copying over a ``struct``? -====================================================================== - -This is a very interesting question. Suppose that we have a contract field set up like such:: - - struct User { - mapping(string => string) comments; - } - - function somefunction public { - User user1; - user1.comments["Hello"] = "World"; - User user2 = user1; - } - -In this case, the mapping of the struct being copied over into ``user2`` is ignored as there is no "list of mapped keys". -Therefore it is not possible to find out which values should be copied over. - How do I initialize a contract with only a specific amount of wei? ================================================================== @@ -273,28 +199,6 @@ In this example:: } } -What is the relationship between ``bytes32`` and ``string``? Why is it that ``bytes32 somevar = "stringliteral";`` works and what does the saved 32-byte hex value mean? -======================================================================================================================================================================== - -The type ``bytes32`` can hold 32 (raw) bytes. In the assignment ``bytes32 samevar = "stringliteral";``, -the string literal is interpreted in its raw byte form and if you inspect ``somevar`` and -see a 32-byte hex value, this is just ``"stringliteral"`` in hex. - -The type ``bytes`` is similar, only that it can change its length. - -Finally, ``string`` is basically identical to ``bytes`` only that it is assumed -to hold the UTF-8 encoding of a real string. Since ``string`` stores the -data in UTF-8 encoding it is quite expensive to compute the number of -characters in the string (the encoding of some characters takes more -than a single byte). Because of that, ``string s; s.length`` is not yet -supported and not even index access ``s[2]``. But if you want to access -the low-level byte encoding of the string, you can use -``bytes(s).length`` and ``bytes(s)[2]`` which will result in the number -of bytes in the UTF-8 encoding of the string (not the number of -characters) and the second byte (not character) of the UTF-8 encoded -string, respectively. - - Can a contract pass an array (static size) or string or ``bytes`` (dynamic size) to another contract? ===================================================================================================== @@ -325,55 +229,6 @@ to create an independent copy of the storage value in memory. On the other hand, ``h(x)`` successfully modifies ``x`` because only a reference and not a copy is passed. -Sometimes, when I try to change the length of an array with ex: ``arrayname.length = 7;`` I get a compiler error ``Value must be an lvalue``. Why? -================================================================================================================================================== - -You can resize a dynamic array in storage (i.e. an array declared at the -contract level) with ``arrayname.length = <some new length>;``. If you get the -"lvalue" error, you are probably doing one of two things wrong. - -1. You might be trying to resize an array in "memory", or - -2. You might be trying to resize a non-dynamic array. - -:: - - pragma solidity >=0.4.18 <0.6.0; - - // This will not compile - contract C { - int8[] dynamicStorageArray; - int8[5] fixedStorageArray; - - function f() public { - int8[] memory memArr; // Case 1 - memArr.length++; // illegal - - int8[5] storage storageArr = fixedStorageArray; // Case 2 - storageArr.length++; // illegal - - int8[] storage storageArr2 = dynamicStorageArray; - storageArr2.length++; // legal - - - } - } - -**Important note:** In Solidity, array dimensions are declared backwards from the way you -might be used to declaring them in C or Java, but they are access as in -C or Java. - -For example, ``int8[][5] somearray;`` are 5 dynamic ``int8`` arrays. - -The reason for this is that ``T[5]`` is always an array of 5 ``T``'s, -no matter whether ``T`` itself is an array or not (this is not the -case in C or Java). - -Is it possible to return an array of strings (``string[]``) from a Solidity function? -===================================================================================== - -Only when ``pragma experimental "ABIEncoderV2";`` is used. - What does the following strange check do in the Custom Token contract? ====================================================================== diff --git a/docs/grammar.txt b/docs/grammar.txt index b9c8ddb9..3d2c9bc3 100644 --- a/docs/grammar.txt +++ b/docs/grammar.txt @@ -72,7 +72,7 @@ WhileStatement = 'while' '(' Expression ')' Statement PlaceholderStatement = '_' SimpleStatement = VariableDefinition | ExpressionStatement ForStatement = 'for' '(' (SimpleStatement)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement -InlineAssemblyStatement = 'assembly' StringLiteral? InlineAssemblyBlock +InlineAssemblyStatement = 'assembly' StringLiteral? AssemblyBlock DoWhileStatement = 'do' Statement 'while' '(' Expression ')' Continue = 'continue' Break = 'break' @@ -152,11 +152,30 @@ Fixed = 'fixed' | ( 'fixed' [0-9]+ 'x' [0-9]+ ) Ufixed = 'ufixed' | ( 'ufixed' [0-9]+ 'x' [0-9]+ ) -InlineAssemblyBlock = '{' AssemblyItem* '}' -AssemblyItem = Identifier | FunctionalAssemblyExpression | InlineAssemblyBlock | AssemblyVariableDeclaration | AssemblyAssignment | AssemblyLabel | NumberLiteral | StringLiteral | HexLiteral -AssemblyExpression = Identifier | FunctionalAssemblyExpression | NumberLiteral | StringLiteral | HexLiteral -AssemblyVariableDeclaration = 'let' Identifier ':=' AssemblyExpression -AssemblyAssignment = ( Identifier ':=' AssemblyExpression ) | ( '=:' Identifier ) -AssemblyLabel = Identifier ':' -FunctionalAssemblyExpression = Identifier '(' AssemblyItem? ( ',' AssemblyItem )* ')' +AssemblyBlock = '{' AssemblyStatement* '}' + +AssemblyStatement = AssemblyBlock + | AssemblyFunctionDefinition + | AssemblyVariableDeclaration + | AssemblyAssignment + | AssemblyIf + | AssemblyExpression + | AssemblySwitch + | AssemblyForLoop + | AssemblyBreakContinue +AssemblyFunctionDefinition = + 'function' Identifier '(' AssemblyIdentifierList? ')' + ( '->' AssemblyIdentifierList )? AssemblyBlock +AssemblyVariableDeclaration = 'let' AssemblyIdentifierList ( ':=' AssemblyExpression )? +AssemblyAssignment = AssemblyIdentifierList ':=' AssemblyExpression +AssemblyExpression = AssemblyFunctionCall | Identifier | Literal +AssemblyIf = 'if' AssemblyExpression AssemblyBlock +AssemblySwitch = 'switch' AssemblyExpression ( Case+ AssemblyDefault? | AssemblyDefault ) +AssemblyCase = 'case' Literal AssemblyBlock +AssemblyDefault = 'default' AssemblyBlock +AssemblyForLoop = 'for' AssemblyBlock AssemblyExpression AssemblyBlock AssemblyBlock +AssemblyBreakContinue = 'break' | 'continue' +AssemblyFunctionCall = Identifier '(' ( AssemblyExpression ( ',' AssemblyExpression )* )? ')' + +AssemblyIdentifierList = Identifier ( ',' Identifier )* diff --git a/docs/index.rst b/docs/index.rst index 17abf4b2..ed931163 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,26 +19,43 @@ user-defined types among other features. With Solidity you can create contracts for uses such as voting, crowdfunding, blind auctions, and multi-signature wallets. -.. note:: - The best way to try out Solidity right now is using - `Remix <https://remix.ethereum.org/>`_ - (it can take a while to load, please be patient). Remix is a web browser - based IDE that allows you to write Solidity smart contracts, then deploy - and run the smart contracts. +Language Documentation +---------------------- + +If you are new to the concept of smart contracts we recommend you start with +:ref:`an example smart contract <simple-smart-contract>` written +in Solidity. When you are ready for more detail, we recommend you read the +:doc:`"Solidity by Example" <solidity-by-example>` and :doc:`"Solidity in Depth" <solidity-in-depth>` sections to learn the core concepts of the language. + +For further reading, try :ref:`the basics of blockchains <blockchain-basics>` +and details of the :ref:`Ethereum Virtual Machine <the-ethereum-virtual-machine>`. + +.. hint:: + You can always try out code examples in your browser with the + `Remix IDE <https://remix.ethereum.org>`_. Remix is a web browser based IDE + that allows you to write Solidity smart contracts, then deploy and run the + smart contracts. It can take a while to load, so please be patient. .. warning:: - Since software is written by humans, it can have bugs. Thus, also - smart contracts should be created following well-known best-practices in - software development. This includes code review, testing, audits and correctness proofs. - Also note that users are sometimes more confident in code than its authors. - Finally, blockchains have their own things to watch out for, so please take - a look at the section :ref:`security_considerations`. + As humans write software, it can have bugs. You should follow established + software development best-practices when writing your smart contracts, this + includes code review, testing, audits, and correctness proofs. Smart contract + users are sometimes more confident with code than their authors, and + blockchains and smart contracts have their own unique issues to + watch out for, so before working on production code, make sure you read the + :ref:`security_considerations` section. + +If you have any questions, you can try searching for answers or asking on the +`Ethereum Stackexchange <https://ethereum.stackexchange.com/>`_, or our `gitter channel <https://gitter.im/ethereum/solidity/>`_. + +Ideas for improving Solidity or this documentation are always welcome, read our :doc:`contributors guide <contributing>` for more details. Translations ------------ -This documentation is translated into several languages by community volunteers -with varying degrees of completeness and up-to-dateness. The English version stands as a reference. +Community volunteers help translate this documentation into several languages. +They have varying degrees of completeness and up-to-dateness. The English +version stands as a reference. * `Simplified Chinese <http://solidity-cn.readthedocs.io>`_ (in progress) * `Spanish <https://solidity-es.readthedocs.io>`_ @@ -46,25 +63,6 @@ with varying degrees of completeness and up-to-dateness. The English version sta * `Korean <http://solidity-kr.readthedocs.io>`_ (in progress) * `French <http://solidity-fr.readthedocs.io>`_ (in progress) -Language Documentation ----------------------- - -On the next pages, we will first see a :ref:`simple smart contract <simple-smart-contract>` written -in Solidity followed by the basics about :ref:`blockchains <blockchain-basics>` -and the :ref:`Ethereum Virtual Machine <the-ethereum-virtual-machine>`. - -The next section will explain several *features* of Solidity by giving -useful :ref:`example contracts <voting>`. -Remember that you can always try out the contracts -`in your browser <https://remix.ethereum.org>`_! - -The fourth and most extensive section will cover all aspects of Solidity in depth. - -If you still have questions, you can try searching or asking on the -`Ethereum Stackexchange <https://ethereum.stackexchange.com/>`_ -site, or come to our `gitter channel <https://gitter.im/ethereum/solidity/>`_. -Ideas for improving Solidity or this documentation are always welcome! - Contents ======== diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index f8de0e8d..2797d8b0 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -115,7 +115,7 @@ Arch Linux also has packages, albeit limited to the latest development version: pacman -S solidity -We distribute the Solidity compiler through Homebrow +We distribute the Solidity compiler through Homebrew as a build-from-source version. Pre-built bottles are currently not supported. diff --git a/docs/introduction-to-smart-contracts.rst b/docs/introduction-to-smart-contracts.rst index 9245300b..34ef012e 100644 --- a/docs/introduction-to-smart-contracts.rst +++ b/docs/introduction-to-smart-contracts.rst @@ -400,7 +400,7 @@ within a word). At the time of expansion, the cost in gas must be paid. Memory i costly the larger it grows (it scales quadratically). The EVM is not a register machine but a stack machine, so all -computations are performed on an data area called the **stack**. It has a maximum size of +computations are performed on a data area called the **stack**. It has a maximum size of 1024 elements and contains words of 256 bits. Access to the stack is limited to the top end in the following way: It is possible to copy one of diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index 9a8bdc3e..ad84b200 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -276,7 +276,7 @@ functions, annotate conditions for formal verification, and provide a function. In the following example we document the title of the contract, the explanation -for the two input parameters and two returned values. +for the two function parameters and two return variables. :: diff --git a/docs/lll.rst b/docs/lll.rst index d9409bf8..16be829e 100644 --- a/docs/lll.rst +++ b/docs/lll.rst @@ -9,6 +9,13 @@ LLL is a low-level language for the EVM with an s-expressions syntax. The Solidity repository contains an LLL compiler, which shares the assembler subsystem with Solidity. However, apart from maintaining that it still compiles, no other improvements are made to it. +It is not built unless specifically requested: + +.. code-block:: bash + + $ cmake -DLLL=ON .. + $ cmake --build . + .. warning:: The LLL codebase is deprecated and will be removed from the Solidity repository in the future. diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 21978ded..017d5b81 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -8,13 +8,17 @@ Miscellaneous Layout of State Variables in Storage ************************************ -Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position ``0``. Multiple items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules: +Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position ``0``. Multiple, contiguous items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules: - The first item in a storage slot is stored lower-order aligned. - Elementary types use only that many bytes that are necessary to store them. - If an elementary type does not fit the remaining part of a storage slot, it is moved to the next storage slot. - Structs and array data always start a new slot and occupy whole slots (but items inside a struct or array are packed tightly according to these rules). +For contracts that use inheritance, the ordering of state variables is determined by the +C3-linearized order of contracts starting with the most base-ward contract. If allowed +by the above rules, state variables from different contracts do share the same storage slot. + .. warning:: When using elements that are smaller than 32 bytes, your contract's gas usage may be higher. This is because the EVM operates on 32 bytes at a time. Therefore, if the element is smaller diff --git a/docs/resources.rst b/docs/resources.rst index e9e65692..4dd617fa 100644 --- a/docs/resources.rst +++ b/docs/resources.rst @@ -21,9 +21,8 @@ Solidity Integrations * Generic: - * `EthFiddle <https://ethfiddle.com/>`_ - Solidity IDE in the Browser. Write and share your solidity code. Uses server-side components. + Solidity IDE in the Browser. Write and share your Solidity code. Uses server-side components. * `Remix <https://remix.ethereum.org/>`_ Browser-based IDE with integrated compiler and Solidity runtime environment without server-side components. @@ -34,6 +33,9 @@ Solidity Integrations * `Solhint <https://github.com/protofire/solhint>`_ Solidity linter that provides security, style guide and best practice rules for smart contract validation. + * `Superblocks Lab <https://lab.superblocks.com/>`_ + Browser-based IDE. Built-in browser-based VM and Metamask integration (one click deployment to Testnet/Mainnet). + * Atom: * `Etheratom <https://github.com/0mkara/etheratom>`_ diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 752e8641..d07452c5 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -647,10 +647,10 @@ Safe Remote Purchase Micropayment Channel ******************** -In this section we will learn how to build a simple implementation -of a payment channel. It use cryptographics signatures to make +In this section we will learn how to build an example implementation +of a payment channel. It uses cryptographic signatures to make repeated transfers of Ether between the same parties secure, instantaneous, and -without transaction fees. To do it we need to understand how to +without transaction fees. For the example, we need to understand how to sign and verify signatures, and setup the payment channel. Creating and verifying signatures @@ -658,88 +658,67 @@ Creating and verifying signatures Imagine Alice wants to send a quantity of Ether to Bob, i.e. Alice is the sender and the Bob is the recipient. + Alice only needs to send cryptographically signed messages off-chain -(e.g. via email) to Bob and it will be very similar to writing checks. - -Signatures are used to authorize transactions, -and they are a general tool that is available to -smart contracts. Alice will build a simple -smart contract that lets her transmit Ether, but -in a unusual way, instead of calling a function herself -to initiate a payment, she will let Bob -do that, and therefore pay the transaction fee. +(e.g. via email) to Bob and it is similar to writing checks. + +Alice and Bob use signatures to authorise transactions, which is possible with smart contracts on Ethereum. +Alice will build a simple smart contract that lets her transmit Ether, but instead of calling a function herself +to initiate a payment, she will let Bob do that, and therefore pay the transaction fee. + The contract will work as follows: 1. Alice deploys the ``ReceiverPays`` contract, attaching enough Ether to cover the payments that will be made. - 2. Alice authorizes a payment by signing a message with their private key. + 2. Alice authorises a payment by signing a message with their private key. 3. Alice sends the cryptographically signed message to Bob. The message does not need to be kept secret - (you will understand it later), and the mechanism for sending it does not matter. + (explained later), and the mechanism for sending it does not matter. 4. Bob claims their payment by presenting the signed message to the smart contract, it verifies the authenticity of the message and then releases the funds. Creating the signature ---------------------- -Alice does not need to interact with Ethereum network to -sign the transaction, the process is completely offline. -In this tutorial, we will sign messages in the browser -using ``web3.js`` and ``MetaMask``. -In particular, we will use the standard way described in `EIP-762 <https://github.com/ethereum/EIPs/pull/712>`_, +Alice does not need to interact with the Ethereum network to sign the transaction, the process is completely offline. +In this tutorial, we will sign messages in the browser using `web3.js <https://github.com/ethereum/web3.js>`_ and `MetaMask <https://metamask.io>`_, using the method described in `EIP-762 <https://github.com/ethereum/EIPs/pull/712>`_, as it provides a number of other security benefits. :: + /// Hashing first makes things easier + var hash = web3.utils.sha3("message to sign"); + web3.eth.personal.sign(hash, web3.eth.defaultAccount, function () { console.log("Signed"); }); - /// Hashing first makes a few things easier - var hash = web3.sha3("message to sign"); - web3.personal.sign(hash, web3.eth.defaultAccount, function () {...}); - - -Note that the ``web3.personal.sign`` prepends the length of the message to the signed data. -Since we hash first, the message will always be exactly 32 bytes long, -and thus this length prefix is always the same, making everything easier. +.. note:: + The ``web3.eth.personal.sign`` prepends the length of the message to the signed data. Since we hash first, the message will always be exactly 32 bytes long, and thus this length prefix is always the same. What to Sign ------------ -For a contract that fulfills payments, the signed message must include: +For a contract that fulfils payments, the signed message must include: - 1. The recipient's address - 2. The amount to be transferred - 3. Protection against replay attacks + 1. The recipient's address. + 2. The amount to be transferred. + 3. Protection against replay attacks. A replay attack is when a signed message is reused to claim authorization for a second action. -To avoid replay attacks we will use the same as in Ethereum transactions +To avoid replay attacks we use the same as in Ethereum transactions themselves, a so-called nonce, which is the number of transactions sent by an account. -The smart contract will check if a nonce is used multiple times. +The smart contract checks if a nonce is used multiple times. -There is another type of replay attacks, it occurs when the -owner deploys a ``ReceiverPays`` smart contract, performs some payments, -and then destroy the contract. Later, she decides to deploy the -``RecipientPays`` smart contract again, but the new contract does not -know the nonces used in the previous deployment, so the attacker -can use the old messages again. +Another type of replay attack can occur when the owner deploys a ``ReceiverPays`` smart contract, makes some payments, and then destroys the contract. Later, they decide to deploy the ``RecipientPays`` smart contract again, but the new contract does not know the nonces used in the previous deployment, so the attacker can use the old messages again. -Alice can protect against it including -the contract's address in the message, and only -messages containing contract's address itself will be accepted. -This functionality can be found in the first two lines of the ``claimPayment()`` function in the full contract -at the end of this chapter. +Alice can protect against this attack by including the contract's address in the message, and only messages containing the contract's address itself will be accepted. You can find an example of this in the first two lines of the ``claimPayment()`` function of the full contract at the end of this section. Packing arguments ----------------- -Now that we have identified what information to include in the -signed message, we are ready to put the message together, hash it, -and sign it. For simplicity, we just concatenate the data. -The -`ethereumjs-abi <https://github.com/ethereumjs/ethereumjs-abi>`_ library provides -a function called ``soliditySHA3`` that mimics the behavior -of Solidity's ``keccak256`` function applied to arguments encoded -using ``abi.encodePacked``. -Putting it all together, here is a JavaScript function that -creates the proper signature for the ``ReceiverPays`` example: +Now that we have identified what information to include in the signed message, +we are ready to put the message together, hash it, and sign it. For simplicity, +we concatenate the data. The `ethereumjs-abi <https://github.com/ethereumjs/ethereumjs-abi>`_ +library provides a function called ``soliditySHA3`` that mimics the behaviour of +Solidity's ``keccak256`` function applied to arguments encoded using ``abi.encodePacked``. +Here is a JavaScript function that creates the proper signature for the ``ReceiverPays`` example: :: @@ -748,46 +727,30 @@ creates the proper signature for the ``ReceiverPays`` example: // nonce can be any unique number to prevent replay attacks // contractAddress is used to prevent cross-contract replay attacks function signPayment(recipient, amount, nonce, contractAddress, callback) { - var hash = "0x" + ethereumjs.ABI.soliditySHA3( + var hash = "0x" + abi.soliditySHA3( ["address", "uint256", "uint256", "address"], [recipient, amount, nonce, contractAddress] ).toString("hex"); - web3.personal.sign(hash, web3.eth.defaultAccount, callback); + web3.eth.personal.sign(hash, web3.eth.defaultAccount, callback); } Recovering the Message Signer in Solidity ----------------------------------------- -In general, ECDSA signatures consist of two parameters, ``r`` and ``s``. -Signatures in Ethereum include a third parameter called ``v``, that can be used -to recover which account's private key was used to sign in the message, -the transaction's sender. Solidity provides a built-in function -`ecrecover <mathematical-and-cryptographic-functions>`_ -that accepts a message along with the ``r``, ``s`` and ``v`` parameters and -returns the address that was used to sign the message. +In general, ECDSA signatures consist of two parameters, ``r`` and ``s``. Signatures in Ethereum include a third parameter called ``v``, that you can use to verify which account's private key was used to sign the message, and the transaction's sender. Solidity provides a built-in function `ecrecover <mathematical-and-cryptographic-functions>`_ that accepts a message along with the ``r``, ``s`` and ``v`` parameters and returns the address that was used to sign the message. Extracting the Signature Parameters ----------------------------------- -Signatures produced by web3.js are the concatenation of ``r``, ``s`` and ``v``, -so the first step is splitting those parameters back out. It can be done on the client, -but doing it inside the smart contract means only one signature parameter -needs to be sent rather than three. -Splitting apart a byte array into component parts is a little messy. -We will use `inline assembly <assembly>`_ to do the job -in the ``splitSignature`` function (the third function in the full contract -at the end of this chapter). +Signatures produced by web3.js are the concatenation of ``r``, ``s`` and ``v``, so the first step is to split these parameters apart. You can do this on the client-side, but doing it inside the smart contract means you only need to send one signature parameter rather than three. Splitting apart a byte array into component parts is a messy, so we use `inline assembly <assembly>`_ to do the job in the ``splitSignature`` function (the third function in the full contract at the end of this section). Computing the Message Hash -------------------------- -The smart contract needs to know exactly what parameters were signed, -and so it must recreate the message from the parameters and use that -for signature verification. The functions ``prefixed`` and -``recoverSigner`` do this and their use can be found in the -``claimPayment`` function. - +The smart contract needs to know exactly what parameters were signed, and so it +must recreate the message from the parameters and use that for signature verification. +The functions ``prefixed`` and ``recoverSigner`` do this in the ``claimPayment`` function. The full contract ----------------- @@ -861,41 +824,26 @@ The full contract Writing a Simple Payment Channel ================================ -Alice will now build a simple but complete implementation of a payment channel. -Payment channels use cryptographic signatures to make repeated transfers -of Ether securely, instantaneously, and without transaction fees. +Alice now builds a simple but complete implementation of a payment channel. Payment channels use cryptographic signatures to make repeated transfers of Ether securely, instantaneously, and without transaction fees. What is a Payment Channel? -------------------------- -Payment channels allow participants to make repeated transfers of Ether without -using transactions. This means that the delays and fees associated with transactions -can be avoided. We are going to explore a simple unidirectional payment channel between -two parties (Alice and Bob). Using it involves three steps: +Payment channels allow participants to make repeated transfers of Ether without using transactions. This means that you can avoid the delays and fees associated with transactions. We are going to explore a simple unidirectional payment channel between two parties (Alice and Bob). It involves three steps: 1. Alice funds a smart contract with Ether. This "opens" the payment channel. 2. Alice signs messages that specify how much of that Ether is owed to the recipient. This step is repeated for each payment. 3. Bob "closes" the payment channel, withdrawing their portion of the Ether and sending the remainder back to the sender. -Note that only steps 1 and 3 require Ethereum transactions, step 2 means that -the sender transmits a cryptographically signed message to the recipient via off chain ways (e.g. email). -This means only two transactions are required to support any number of transfers. +.. note:: + Only steps 1 and 3 require Ethereum transactions, step 2 means that the sender transmits a cryptographically signed message to the recipient via off chain methods (e.g. email). This means only two transactions are required to support any number of transfers. -Bob is guaranteed to receive their funds because the smart contract escrows -the Ether and honors a valid signed message. The smart contract also enforces a timeout, -so Alice is guaranteed to eventually recover their funds even if the recipient refuses -to close the channel. -It is up to the participants in a payment channel to decide how long to keep it open. -For a short-lived transaction, such as paying an internet cafe for each minute of network access, -or for a longer relationship, such as paying an employee an hourly wage, a payment could last for months or years. +Bob is guaranteed to receive their funds because the smart contract escrows the Ether and honours a valid signed message. The smart contract also enforces a timeout, so Alice is guaranteed to eventually recover their funds even if the recipient refuses to close the channel. It is up to the participants in a payment channel to decide how long to keep it open. For a short-lived transaction, such as paying an internet café for each minute of network access, or for a longer relationship, such as paying an employee an hourly wage, a payment could last for months or years. Opening the Payment Channel --------------------------- -To open the payment channel, Alice deploys the smart contract, -attaching the Ether to be escrowed and specifying the intendend recipient -and a maximum duration for the channel to exist. It is the function -``SimplePaymentChannel`` in the contract, that is at the end of this chapter. +To open the payment channel, Alice deploys the smart contract, attaching the Ether to be escrowed and specifying the intended recipient and a maximum duration for the channel to exist. This is the function ``SimplePaymentChannel`` in the contract, at the end of this section. Making Payments --------------- @@ -910,27 +858,26 @@ Each message includes the following information: * The total amount of Ether that is owed the recipient so far. A payment channel is closed just once, at the end of a series of transfers. -Because of this, only one of the messages sent will be redeemed. This is why +Because of this, only one of the messages sent is redeemed. This is why each message specifies a cumulative total amount of Ether owed, rather than the amount of the individual micropayment. The recipient will naturally choose to redeem the most recent message because that is the one with the highest total. -The nonce per-message is not needed anymore, because the smart contract will -only honor a single message. The address of the smart contract is still used +The nonce per-message is not needed anymore, because the smart contract only honors a single message. The address of the smart contract is still used to prevent a message intended for one payment channel from being used for a different channel. -Here is the modified javascript code to cryptographically sign a message from the previous chapter: +Here is the modified JavaScript code to cryptographically sign a message from the previous section: :: function constructPaymentMessage(contractAddress, amount) { - return ethereumjs.ABI.soliditySHA3( + return abi.soliditySHA3( ["address", "uint256"], [contractAddress, amount] ); } function signMessage(message, callback) { - web3.personal.sign( + web3.eth.personal.sign( "0x" + message.toString("hex"), web3.eth.defaultAccount, callback @@ -951,18 +898,15 @@ Closing the Payment Channel When Bob is ready to receive their funds, it is time to close the payment channel by calling a ``close`` function on the smart contract. -Closing the channel pays the recipient the Ether they are owed and destroys the contract, -sending any remaining Ether back to Alice. -To close the channel, Bob needs to provide a message signed by Alice. +Closing the channel pays the recipient the Ether they are owed and destroys the contract, sending any remaining Ether back to Alice. To close the channel, Bob needs to provide a message signed by Alice. The smart contract must verify that the message contains a valid signature from the sender. The process for doing this verification is the same as the process the recipient uses. The Solidity functions ``isValidSignature`` and ``recoverSigner`` work just like their -JavaScript counterparts in the previous section. The latter is borrowed from the -``ReceiverPays`` contract in the previous chapter. +JavaScript counterparts in the previous section, with the latter function borrowed from the ``ReceiverPays`` contract. -The ``close`` function can only be called by the payment channel recipient, -who will naturally pass the most recent payment message because that message +Only the payment channel recipient can call the ``close`` function, +who naturally passes the most recent payment message because that message carries the highest total owed. If the sender were allowed to call this function, they could provide a message with a lower amount and cheat the recipient out of what they are owed. @@ -977,13 +921,11 @@ Channel Expiration Bob can close the payment channel at any time, but if they fail to do so, Alice needs a way to recover their escrowed funds. An *expiration* time was set at the time of contract deployment. Once that time is reached, Alice can call -``claimTimeout`` to recover their funds. You can see the ``claimTimeout`` function in the -full contract. +``claimTimeout`` to recover their funds. You can see the ``claimTimeout`` function in the full contract. After this function is called, Bob can no longer receive any Ether, so it is important that Bob closes the channel before the expiration is reached. - The full contract ----------------- @@ -1081,16 +1023,15 @@ The full contract } -Note: The function ``splitSignature`` is very simple and does not use all security checks. -A real implementation should use a more rigorously tested library, such as -openzepplin's `version <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ECRecovery.sol>`_ of this code. - - +.. note:: + The function ``splitSignature`` does not use all security + checks. A real implementation should use a more rigorously tested library, + such as openzepplin's `version <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ECRecovery.sol>`_ of this code. Verifying Payments ------------------ -Unlike in our previous chapter, messages in a payment channel aren't +Unlike in the previous section, messages in a payment channel aren't redeemed right away. The recipient keeps track of the latest message and redeems it when it's time to close the payment channel. This means it's critical that the recipient perform their own verification of each message. @@ -1105,10 +1046,8 @@ The recipient should verify each message using the following process: 4. Verify that the signature is valid and comes from the payment channel sender. We'll use the `ethereumjs-util <https://github.com/ethereumjs/ethereumjs-util>`_ -library to write this verifications. The final step can be done a number of ways, -but if it's being done in **JavaScript**. -The following code borrows the `constructMessage` function from the signing **JavaScript code** -above: +library to write this verification. The final step can be done a number of ways, +and we use JavaScript. The following code borrows the `constructMessage` function from the signing **JavaScript code** above: :: diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index 582e5338..569639e0 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -56,7 +56,8 @@ Functions are the executable units of code within a contract. :ref:`function-calls` can happen internally or externally and have different levels of :ref:`visibility<visibility-and-getters>` -towards other contracts. +towards other contracts. :ref:`Functions<functions>` accept :ref:`parameters and return variables<function-parameters-return-variables>` to pass parameters +and values between them. .. _structure-function-modifiers: diff --git a/docs/style-guide.rst b/docs/style-guide.rst index 7b48ccad..68fee871 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -809,7 +809,23 @@ possible permutations for function declarations. Mappings ======== -TODO +In variable declarations, do not separate the keyword ``mapping`` from its +type by a space. Do not separate any nested ``mapping`` keyword from its type by +whitespace. + +Yes:: + + mapping(uint => uint) map; + mapping(address => bool) registeredAddresses; + mapping(uint => mapping(bool => Data[])) public data; + mapping(uint => mapping(uint => s)) data; + +No:: + + mapping (uint => uint) map; + mapping( address => bool ) registeredAddresses; + mapping (uint => mapping (bool => Data[])) public data; + mapping(uint => mapping (uint => s)) data; Variable Declarations ===================== diff --git a/docs/types.rst b/docs/types.rst index 34b94b88..f67a6d1a 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -13,6 +13,11 @@ Solidity provides several elementary types which can be combined to form complex In addition, types can interact with each other in expressions containing operators. For a quick reference of the various operators, see :ref:`order`. +The concept of "undefined" or "null" values does not exist in Solidity, but newly +declared variables always have a :ref:`default value<default-value>` dependent +on its type. To handle any unexpected values, you should use the :ref:`revert function<assert-and-require>` to revert the whole transaction, or return a +tuple with a second `bool` value denoting success. + .. index:: ! value type, ! type;value Value Types @@ -253,7 +258,7 @@ Send is the low-level counterpart of ``transfer``. If the execution fails, the c In order to interface with contracts that do not adhere to the ABI, or to get more direct control over the encoding, the functions ``call``, ``delegatecall`` and ``staticcall`` are provided. -They all take a single ``bytes memory`` argument as input and +They all take a single ``bytes memory`` parameter and return the success condition (as a ``bool``) and the returned data (``bytes memory``). The functions ``abi.encode``, ``abi.encodePacked``, ``abi.encodeWithSelector`` @@ -273,22 +278,22 @@ Example:: when the call returns. The regular way to interact with other contracts is to call a function on a contract object (``x.f()``). -:: note:: +.. note:: Previous versions of Solidity allowed these functions to receive arbitrary arguments and would also handle a first argument of type ``bytes4`` differently. These edge cases were removed in version 0.5.0. It is possible to adjust the supplied gas with the ``.gas()`` modifier:: - namReg.call.gas(1000000)(abi.encodeWithSignature("register(string)", "MyName")); + address(nameReg).call.gas(1000000)(abi.encodeWithSignature("register(string)", "MyName")); Similarly, the supplied Ether value can be controlled too:: - nameReg.call.value(1 ether)(abi.encodeWithSignature("register(string)", "MyName")); + address(nameReg).call.value(1 ether)(abi.encodeWithSignature("register(string)", "MyName")); Lastly, these modifiers can be combined. Their order does not matter:: - nameReg.call.gas(1000000).value(1 ether)(abi.encodeWithSignature("register(string)", "MyName")); + address(nameReg).call.gas(1000000).value(1 ether)(abi.encodeWithSignature("register(string)", "MyName")); In a similar way, the function ``delegatecall`` can be used: the difference is that only the code of the given address is used, all other aspects (storage, balance, ...) are taken from the current contract. The purpose of ``delegatecall`` is to use library code which is stored in another contract. The user has to ensure that the layout of storage in both contracts is suitable for delegatecall to be used. @@ -460,11 +465,13 @@ a non-rational number). .. index:: literal, literal;string, string .. _string_literals: -String Literals ---------------- +String Literals and Types +------------------------- String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``). They do not imply trailing zeroes as in C; ``"foo"`` represents three bytes, not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``. +For example, with ``bytes32 samevar = "stringliteral"`` the string literal is interpreted in its raw byte form when assigned to a ``bytes32`` type. + String literals support the following escape characters: - ``\<newline>`` (escapes an actual newline) @@ -857,13 +864,20 @@ or create a new memory array and copy every element. } } -.. index:: ! array;literals, !inline;arrays +.. index:: ! array;literals, ! inline;arrays + +Array Literals +^^^^^^^^^^^^^^ + +An array literal is a comma-separated list of one or more expressions, enclosed +in square brackets (``[...]``). For example ``[1, a, f(3)]``. There must be a +common type all elements can be implicitly converted to. This is the elementary +type of the array. -Array Literals / Inline Arrays -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Array literals are always statically-sized memory arrays. -Array literals are arrays that are written as an expression and are not -assigned to a variable right away. +In the example below, the type of ``[1, 2, 3]`` is +``uint8[3] memory``. Because the type of each of these constants is ``uint8``, if you want the result to be a ``uint[3] memory`` type, you need to convert the first element to ``uint``. :: @@ -878,13 +892,7 @@ assigned to a variable right away. } } -The type of an array literal is a memory array of fixed size whose base -type is the common type of the given elements. The type of ``[1, 2, 3]`` is -``uint8[3] memory``, because the type of each of these constants is ``uint8``. -Because of that, it is necessary to convert the first element in the example -above to ``uint``. Note that currently, fixed size memory arrays cannot -be assigned to dynamically-sized memory arrays, i.e. the following is not -possible: +Fixed size memory arrays cannot be assigned to dynamically-sized memory arrays, i.e. the following is not possible: :: @@ -899,8 +907,8 @@ possible: } } -It is planned to remove this restriction in the future but currently creates -some complications because of how arrays are passed in the ABI. +It is planned to remove this restriction in the future, but it creates some +complications because of how arrays are passed in the ABI. .. index:: ! array;length, length, push, pop, !array;push, !array;pop @@ -913,7 +921,9 @@ Members For dynamically-sized arrays (only available for storage), this member can be assigned to resize the array. Accessing elements outside the current length does not automatically resize the array and instead causes a failing assertion. Increasing the length adds new zero-initialised elements to the array. - Reducing the length performs an implicit :ref:``delete`` on each of the removed elements. + Reducing the length performs an implicit :ref:``delete`` on each of the + removed elements. If you try to resize a non-dynamic array that isn't in + storage, you receive a ``Value must be an lvalue`` error. **push**: Dynamic storage arrays and ``bytes`` (not ``string``) have a member function called ``push`` that you can use to append an element at the end of the array. The element will be zero-initialised. The function returns the new length. **pop**: diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 7f62e71e..336aaf77 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -43,8 +43,8 @@ library has to be updated by an external oracle. .. note:: The suffix ``years`` has been removed in version 0.5.0 due to the reasons above. -These suffixes cannot be applied to variables. If you want to -interpret some input variable in e.g. days, you can do it in the following way:: +These suffixes cannot be applied to variables. For example, if you want to +interpret a function parameter in days, you can in the following way:: function f(uint start, uint daysAfter) public { if (now >= start + daysAfter * 1 days) { @@ -125,7 +125,7 @@ ABI Encoding and Decoding Functions These encoding functions can be used to craft data for external function calls without actually calling an external function. Furthermore, ``keccak256(abi.encodePacked(a, b))`` is a way to compute the hash of structured data (although be aware that it is possible to - craft a "hash collision" using different inputs types). + craft a "hash collision" using different function parameter types). See the documentation about the :ref:`ABI <ABI>` and the :ref:`tightly packed encoding <abi_packed_mode>` for details about the encoding. @@ -240,4 +240,3 @@ Furthermore, all functions of the current contract are callable directly includi .. note:: Prior to version 0.5.0, there was a function called ``suicide`` with the same semantics as ``selfdestruct``. - diff --git a/docs/yul.rst b/docs/yul.rst index 9e9fac8e..9e50f126 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -369,10 +369,10 @@ The following functions must be available: +---------------------------------------------+-----------------------------------------------------------------+ | gtu256(x:u256, y:u256) -> z:bool | true if x > y, false otherwise | +---------------------------------------------+-----------------------------------------------------------------+ -| sltu256(x:s256, y:s256) -> z:bool | true if x < y, false otherwise | +| lts256(x:s256, y:s256) -> z:bool | true if x < y, false otherwise | | | (for signed numbers in two's complement) | +---------------------------------------------+-----------------------------------------------------------------+ -| sgtu256(x:s256, y:s256) -> z:bool | true if x > y, false otherwise | +| gts256(x:s256, y:s256) -> z:bool | true if x > y, false otherwise | | | (for signed numbers in two's complement) | +---------------------------------------------+-----------------------------------------------------------------+ | equ256(x:u256, y:u256) -> z:bool | true if x == y, false otherwise | @@ -391,7 +391,7 @@ The following functions must be available: +---------------------------------------------+-----------------------------------------------------------------+ | shru256(x:u256, y:u256) -> z:u256 | logical right shift of x by y | +---------------------------------------------+-----------------------------------------------------------------+ -| saru256(x:u256, y:u256) -> z:u256 | arithmetic right shift of x by y | +| sars256(x:s256, y:u256) -> z:u256 | arithmetic right shift of x by y | +---------------------------------------------+-----------------------------------------------------------------+ | byte(n:u256, x:u256) -> v:u256 | nth byte of x, where the most significant byte is the 0th byte | | | Cannot this be just replaced by and256(shr256(n, x), 0xff) and | @@ -515,6 +515,16 @@ The following functions must be available: +---------------------------------------------+-----------------------------------------------------------------+ | keccak256(p:u256, s:u256) -> v:u256 | keccak(mem[p...(p+s))) | +---------------------------------------------+-----------------------------------------------------------------+ +| *Object access* | | ++---------------------------------------------+-----------------------------------------------------------------+ +| datasize(name:string) -> size:u256 | size of the data object in bytes, name has to be string literal | ++---------------------------------------------+-----------------------------------------------------------------+ +| dataoffset(name:string) -> offset:u256 | offset of the data object inside the data area in bytes, | +| | name has to be string literal | ++---------------------------------------------+-----------------------------------------------------------------+ +| datacopy(dst:u256, src:u256, len:u256) | copy len bytes from the data area starting at offset src bytes | +| | to memory at position dst | ++---------------------------------------------+-----------------------------------------------------------------+ Backends -------- @@ -540,12 +550,18 @@ TBD Specification of Yul Object =========================== +Yul objects are used to group named code and data sections. +The functions ``datasize``, ``dataoffset`` and ``datacopy`` +can be used to access these sections from within code. +Hex strings can be used to specify data in hex encoding, +regular strings in native encoding. For code, +``datacopy`` will access its assembled binary representation. + Grammar:: - TopLevelObject = 'object' '{' Code? ( Object | Data )* '}' - Object = 'object' StringLiteral '{' Code? ( Object | Data )* '}' + Object = 'object' StringLiteral '{' Code ( Object | Data )* '}' Code = 'code' Block - Data = 'data' StringLiteral HexLiteral + Data = 'data' StringLiteral ( HexLiteral | StringLiteral ) HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'') StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"' @@ -558,14 +574,28 @@ An example Yul Object is shown below: // Code consists of a single object. A single "code" node is the code of the object. // Every (other) named object or data section is serialized and // made accessible to the special built-in functions datacopy / dataoffset / datasize - object { + // Access to nested objects can be performed by joining the names using ``.``. + // The current object and sub-objects and data items inside the current object + // are in scope without nested access. + object "Contract1" { code { - let size = datasize("runtime") + // first create "runtime.Contract2" + let size = datasize("runtime.Contract2") let offset = allocate(size) // This will turn into a memory->memory copy for eWASM and // a codecopy for EVM - datacopy(dataoffset("runtime"), offset, size) - // this is a constructor and the runtime code is returned + datacopy(offset, dataoffset("runtime.Contract2"), size) + // constructor parameter is a single number 0x1234 + mstore(add(offset, size), 0x1234) + create(offset, add(size, 32)) + + // now return the runtime object (this is + // constructor code) + size := datasize("runtime") + offset := allocate(size) + // This will turn into a memory->memory copy for eWASM and + // a codecopy for EVM + datacopy(offset, dataoffset("runtime"), size) return(offset, size) } @@ -579,7 +609,7 @@ An example Yul Object is shown below: let offset = allocate(size) // This will turn into a memory->memory copy for eWASM and // a codecopy for EVM - datacopy(dataoffset("Contract2"), offset, size) + datacopy(offset, dataoffset("Contract2"), size) // constructor parameter is a single number 0x1234 mstore(add(offset, size), 0x1234) create(offset, add(size, 32)) |