diff options
-rw-r--r-- | docs/contracts.rst | 400 | ||||
-rw-r--r-- | docs/contracts/functions.rst | 398 | ||||
-rw-r--r-- | docs/examples/blind-auction.rst | 339 | ||||
-rw-r--r-- | docs/frequently-asked-questions.rst | 36 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 342 | ||||
-rw-r--r-- | docs/types.rst | 187 | ||||
-rw-r--r-- | docs/types/conversion.rst | 127 | ||||
-rw-r--r-- | docs/types/mapping-types.rst | 58 |
8 files changed, 926 insertions, 961 deletions
diff --git a/docs/contracts.rst b/docs/contracts.rst index 859cd9e9..646e4cdc 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -19,405 +19,7 @@ inaccessible. .. include:: contracts/function-modifiers.rst .. include:: contracts/constant-state-variables.rst - -.. index:: ! functions - -.. _functions: - -********* -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. -The number of components must be the same as the number of return types. - -.. index:: ! view function, function;view - -.. _view-functions: - -View Functions -============== - -Functions can be declared ``view`` in which case they promise not to modify the state. - -.. note:: - If the compiler's EVM target is Byzantium or newer (default) the opcode - ``STATICCALL`` is used for ``view`` functions which enforces the state - to stay unmodified as part of the EVM execution. For library ``view`` functions - ``DELEGATECALL`` is used, because there is no combined ``DELEGATECALL`` and ``STATICCALL``. - This means library ``view`` functions do not have run-time checks that prevent state - modifications. This should not impact security negatively because library code is - usually known at compile-time and the static checker performs compile-time checks. - -The following statements are considered modifying the state: - -#. Writing to state variables. -#. :ref:`Emitting events <events>`. -#. :ref:`Creating other contracts <creating-contracts>`. -#. Using ``selfdestruct``. -#. Sending Ether via calls. -#. Calling any function not marked ``view`` or ``pure``. -#. Using low-level calls. -#. Using inline assembly that contains certain opcodes. - -:: - - pragma solidity ^0.5.0; - - contract C { - function f(uint a, uint b) public view returns (uint) { - return a * (b + 42) + now; - } - } - -.. note:: - ``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0. - -.. note:: - Getter methods are automatically marked ``view``. - -.. note:: - Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode - for ``view`` functions. - This enabled state modifications in ``view`` functions through the use of - invalid explicit type conversions. - By using ``STATICCALL`` for ``view`` functions, modifications to the - state are prevented on the level of the EVM. - -.. index:: ! pure function, function;pure - -.. _pure-functions: - -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, - 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: - -#. Reading from state variables. -#. Accessing ``address(this).balance`` or ``<address>.balance``. -#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``). -#. Calling any function not marked ``pure``. -#. Using inline assembly that contains certain opcodes. - -:: - - pragma solidity ^0.5.0; - - contract C { - function f(uint a, uint b) public pure returns (uint) { - return a * (b + 42); - } - } - -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. - This enabled state modifications in ``pure`` functions through the use of - invalid explicit type conversions. - By using ``STATICCALL`` for ``pure`` functions, modifications to the - state are prevented on the level of the EVM. - -.. 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 - at runtime is actually of that type. - -.. index:: ! fallback function, function;fallback - -.. _fallback-function: - -Fallback Function -================= - -A contract can have exactly one unnamed function. This function cannot have -arguments, cannot return anything and has to have ``external`` visibility. -It is executed on a call to the contract if none of the other -functions match the given function identifier (or if no data was supplied at -all). - -Furthermore, this function is executed whenever the contract receives plain -Ether (without data). Additionally, in order to receive Ether, the fallback function -must be marked ``payable``. If no such function exists, the contract cannot receive -Ether through regular transactions. - -In the worst case, the fallback function can only rely on 2300 gas being -available (for example when `send` or `transfer` is used), leaving little -room to perform other operations except basic logging. The following operations -will consume more gas than the 2300 gas stipend: - -- Writing to storage -- Creating a contract -- Calling an external function which consumes a large amount of gas -- Sending Ether - -Like any function, the fallback function can execute complex operations as long as there is enough gas passed on to it. - -.. note:: - Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve - 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 - before Solidity v0.4.0). So if you want your contract to receive Ether, - you have to implement a payable fallback function. - -.. warning:: - A contract without a payable fallback function can receive Ether as a recipient of a `coinbase transaction` (aka `miner block reward`) - or as a destination of a ``selfdestruct``. - - A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of the EVM and Solidity cannot work around it. - - It also means that ``address(this).balance`` can be higher than the sum of some manual accounting implemented in a contract (i.e. having a counter updated in the fallback function). - -:: - - pragma solidity ^0.5.0; - - contract Test { - // This function is called for all messages sent to - // this contract (there is no other function). - // Sending Ether to this contract will cause an exception, - // because the fallback function does not have the `payable` - // modifier. - function() external { x = 1; } - uint x; - } - - - // This contract keeps all Ether sent to it with no way - // to get it back. - contract Sink { - function() external payable { } - } - - contract Caller { - function callTest(Test test) public returns (bool) { - (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()")); - require(success); - // results in test.x becoming == 1. - - // address(test) will not allow to call ``send`` directly, since ``test`` has no payable - // fallback function. It has to be converted to the ``address payable`` type via an - // intermediate conversion to ``uint160`` to even allow calling ``send`` on it. - address payable testPayable = address(uint160(address(test))); - - // If someone sends ether to that contract, - // the transfer will fail, i.e. this returns false here. - return testPayable.send(2 ether); - } - } - -.. index:: ! overload - -.. _overload-function: - -Function Overloading -==================== - -A contract can have multiple functions of the same name but with different parameter -types. -This process is called "overloading" and also applies to inherited functions. -The following example shows overloading of the function -``f`` in the scope of contract ``A``. - -:: - - pragma solidity >=0.4.16 <0.6.0; - - contract A { - function f(uint _in) public pure returns (uint out) { - out = _in; - } - - function f(uint _in, bool _really) public pure returns (uint out) { - if (_really) - out = _in; - } - } - -Overloaded functions are also present in the external interface. It is an error if two -externally visible functions differ by their Solidity types but not by their external types. - -:: - - pragma solidity >=0.4.16 <0.6.0; - - // This will not compile - contract A { - function f(B _in) public pure returns (B out) { - out = _in; - } - - function f(address _in) public pure returns (address out) { - out = _in; - } - } - - contract B { - } - - -Both ``f`` function overloads above end up accepting the address type for the ABI although -they are considered different inside Solidity. - -Overload resolution and Argument matching ------------------------------------------ - -Overloaded functions are selected by matching the function declarations in the current scope -to the arguments supplied in the function call. Functions are selected as overload candidates -if all arguments can be implicitly converted to the expected types. If there is not exactly one -candidate, resolution fails. - -.. note:: - Return parameters are not taken into account for overload resolution. - -:: - - pragma solidity >=0.4.16 <0.6.0; - - contract A { - function f(uint8 _in) public pure returns (uint8 out) { - out = _in; - } - - function f(uint256 _in) public pure returns (uint256 out) { - out = _in; - } - } - -Calling ``f(50)`` would create a type error since ``50`` can be implicitly converted both to ``uint8`` -and ``uint256`` types. On another hand ``f(256)`` would resolve to ``f(uint256)`` overload as ``256`` cannot be implicitly -converted to ``uint8``. +.. include:: contracts/functions.rst .. include:: contracts/events.rst diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst new file mode 100644 index 00000000..76245952 --- /dev/null +++ b/docs/contracts/functions.rst @@ -0,0 +1,398 @@ +.. index:: ! functions + +.. _functions: + +********* +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. +The number of components must be the same as the number of return types. + +.. index:: ! view function, function;view + +.. _view-functions: + +View Functions +============== + +Functions can be declared ``view`` in which case they promise not to modify the state. + +.. note:: + If the compiler's EVM target is Byzantium or newer (default) the opcode + ``STATICCALL`` is used for ``view`` functions which enforces the state + to stay unmodified as part of the EVM execution. For library ``view`` functions + ``DELEGATECALL`` is used, because there is no combined ``DELEGATECALL`` and ``STATICCALL``. + This means library ``view`` functions do not have run-time checks that prevent state + modifications. This should not impact security negatively because library code is + usually known at compile-time and the static checker performs compile-time checks. + +The following statements are considered modifying the state: + +#. Writing to state variables. +#. :ref:`Emitting events <events>`. +#. :ref:`Creating other contracts <creating-contracts>`. +#. Using ``selfdestruct``. +#. Sending Ether via calls. +#. Calling any function not marked ``view`` or ``pure``. +#. Using low-level calls. +#. Using inline assembly that contains certain opcodes. + +:: + + pragma solidity ^0.5.0; + + contract C { + function f(uint a, uint b) public view returns (uint) { + return a * (b + 42) + now; + } + } + +.. note:: + ``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0. + +.. note:: + Getter methods are automatically marked ``view``. + +.. note:: + Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode + for ``view`` functions. + This enabled state modifications in ``view`` functions through the use of + invalid explicit type conversions. + By using ``STATICCALL`` for ``view`` functions, modifications to the + state are prevented on the level of the EVM. + +.. index:: ! pure function, function;pure + +.. _pure-functions: + +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, + 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: + +#. Reading from state variables. +#. Accessing ``address(this).balance`` or ``<address>.balance``. +#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``). +#. Calling any function not marked ``pure``. +#. Using inline assembly that contains certain opcodes. + +:: + + pragma solidity ^0.5.0; + + contract C { + function f(uint a, uint b) public pure returns (uint) { + return a * (b + 42); + } + } + +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. + This enabled state modifications in ``pure`` functions through the use of + invalid explicit type conversions. + By using ``STATICCALL`` for ``pure`` functions, modifications to the + state are prevented on the level of the EVM. + +.. 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 + at runtime is actually of that type. + +.. index:: ! fallback function, function;fallback + +.. _fallback-function: + +Fallback Function +================= + +A contract can have exactly one unnamed function. This function cannot have +arguments, cannot return anything and has to have ``external`` visibility. +It is executed on a call to the contract if none of the other +functions match the given function identifier (or if no data was supplied at +all). + +Furthermore, this function is executed whenever the contract receives plain +Ether (without data). Additionally, in order to receive Ether, the fallback function +must be marked ``payable``. If no such function exists, the contract cannot receive +Ether through regular transactions. + +In the worst case, the fallback function can only rely on 2300 gas being +available (for example when `send` or `transfer` is used), leaving little +room to perform other operations except basic logging. The following operations +will consume more gas than the 2300 gas stipend: + +- Writing to storage +- Creating a contract +- Calling an external function which consumes a large amount of gas +- Sending Ether + +Like any function, the fallback function can execute complex operations as long as there is enough gas passed on to it. + +.. note:: + Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve + 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 + before Solidity v0.4.0). So if you want your contract to receive Ether, + you have to implement a payable fallback function. + +.. warning:: + A contract without a payable fallback function can receive Ether as a recipient of a `coinbase transaction` (aka `miner block reward`) + or as a destination of a ``selfdestruct``. + + A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of the EVM and Solidity cannot work around it. + + It also means that ``address(this).balance`` can be higher than the sum of some manual accounting implemented in a contract (i.e. having a counter updated in the fallback function). + +:: + + pragma solidity ^0.5.0; + + contract Test { + // This function is called for all messages sent to + // this contract (there is no other function). + // Sending Ether to this contract will cause an exception, + // because the fallback function does not have the `payable` + // modifier. + function() external { x = 1; } + uint x; + } + + + // This contract keeps all Ether sent to it with no way + // to get it back. + contract Sink { + function() external payable { } + } + + contract Caller { + function callTest(Test test) public returns (bool) { + (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()")); + require(success); + // results in test.x becoming == 1. + + // address(test) will not allow to call ``send`` directly, since ``test`` has no payable + // fallback function. It has to be converted to the ``address payable`` type via an + // intermediate conversion to ``uint160`` to even allow calling ``send`` on it. + address payable testPayable = address(uint160(address(test))); + + // If someone sends ether to that contract, + // the transfer will fail, i.e. this returns false here. + return testPayable.send(2 ether); + } + } + +.. index:: ! overload + +.. _overload-function: + +Function Overloading +==================== + +A contract can have multiple functions of the same name but with different parameter +types. +This process is called "overloading" and also applies to inherited functions. +The following example shows overloading of the function +``f`` in the scope of contract ``A``. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + contract A { + function f(uint _in) public pure returns (uint out) { + out = _in; + } + + function f(uint _in, bool _really) public pure returns (uint out) { + if (_really) + out = _in; + } + } + +Overloaded functions are also present in the external interface. It is an error if two +externally visible functions differ by their Solidity types but not by their external types. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + // This will not compile + contract A { + function f(B _in) public pure returns (B out) { + out = _in; + } + + function f(address _in) public pure returns (address out) { + out = _in; + } + } + + contract B { + } + + +Both ``f`` function overloads above end up accepting the address type for the ABI although +they are considered different inside Solidity. + +Overload resolution and Argument matching +----------------------------------------- + +Overloaded functions are selected by matching the function declarations in the current scope +to the arguments supplied in the function call. Functions are selected as overload candidates +if all arguments can be implicitly converted to the expected types. If there is not exactly one +candidate, resolution fails. + +.. note:: + Return parameters are not taken into account for overload resolution. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + contract A { + function f(uint8 _in) public pure returns (uint8 out) { + out = _in; + } + + function f(uint256 _in) public pure returns (uint256 out) { + out = _in; + } + } + +Calling ``f(50)`` would create a type error since ``50`` can be implicitly converted both to ``uint8`` +and ``uint256`` types. On another hand ``f(256)`` would resolve to ``f(uint256)`` overload as ``256`` cannot be implicitly +converted to ``uint8``. diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst new file mode 100644 index 00000000..70d95ad6 --- /dev/null +++ b/docs/examples/blind-auction.rst @@ -0,0 +1,339 @@ +.. index:: auction;blind, auction;open, blind auction, open auction + +************* +Blind Auction +************* + +In this section, we will show how easy it is to create a +completely blind auction contract on Ethereum. +We will start with an open auction where everyone +can see the bids that are made and then extend this +contract into a blind auction where it is not +possible to see the actual bid until the bidding +period ends. + +.. _simple_auction: + +Simple Open Auction +=================== + +The general idea of the following simple auction contract +is that everyone can send their bids during +a bidding period. The bids already include sending +money / ether in order to bind the bidders to their +bid. If the highest bid is raised, the previously +highest bidder gets her money back. +After the end of the bidding period, the +contract has to be called manually for the +beneficiary to receive their money - contracts cannot +activate themselves. + +:: + + pragma solidity >=0.4.22 <0.6.0; + + contract SimpleAuction { + // Parameters of the auction. Times are either + // absolute unix timestamps (seconds since 1970-01-01) + // or time periods in seconds. + address payable public beneficiary; + uint public auctionEndTime; + + // Current state of the auction. + address public highestBidder; + uint public highestBid; + + // Allowed withdrawals of previous bids + mapping(address => uint) pendingReturns; + + // Set to true at the end, disallows any change. + // By default initialized to `false`. + bool ended; + + // Events that will be emitted on changes. + event HighestBidIncreased(address bidder, uint amount); + event AuctionEnded(address winner, uint amount); + + // The following is a so-called natspec comment, + // recognizable by the three slashes. + // It will be shown when the user is asked to + // confirm a transaction. + + /// Create a simple auction with `_biddingTime` + /// seconds bidding time on behalf of the + /// beneficiary address `_beneficiary`. + constructor( + uint _biddingTime, + address payable _beneficiary + ) public { + beneficiary = _beneficiary; + auctionEndTime = now + _biddingTime; + } + + /// Bid on the auction with the value sent + /// together with this transaction. + /// The value will only be refunded if the + /// auction is not won. + function bid() public payable { + // No arguments are necessary, all + // information is already part of + // the transaction. The keyword payable + // is required for the function to + // be able to receive Ether. + + // Revert the call if the bidding + // period is over. + require( + now <= auctionEndTime, + "Auction already ended." + ); + + // If the bid is not higher, send the + // money back. + require( + msg.value > highestBid, + "There already is a higher bid." + ); + + if (highestBid != 0) { + // Sending back the money by simply using + // highestBidder.send(highestBid) is a security risk + // because it could execute an untrusted contract. + // It is always safer to let the recipients + // withdraw their money themselves. + pendingReturns[highestBidder] += highestBid; + } + highestBidder = msg.sender; + highestBid = msg.value; + emit HighestBidIncreased(msg.sender, msg.value); + } + + /// Withdraw a bid that was overbid. + function withdraw() public returns (bool) { + uint amount = pendingReturns[msg.sender]; + if (amount > 0) { + // It is important to set this to zero because the recipient + // can call this function again as part of the receiving call + // before `send` returns. + pendingReturns[msg.sender] = 0; + + if (!msg.sender.send(amount)) { + // No need to call throw here, just reset the amount owing + pendingReturns[msg.sender] = amount; + return false; + } + } + return true; + } + + /// End the auction and send the highest bid + /// to the beneficiary. + function auctionEnd() public { + // It is a good guideline to structure functions that interact + // with other contracts (i.e. they call functions or send Ether) + // into three phases: + // 1. checking conditions + // 2. performing actions (potentially changing conditions) + // 3. interacting with other contracts + // If these phases are mixed up, the other contract could call + // back into the current contract and modify the state or cause + // effects (ether payout) to be performed multiple times. + // If functions called internally include interaction with external + // contracts, they also have to be considered interaction with + // external contracts. + + // 1. Conditions + require(now >= auctionEndTime, "Auction not yet ended."); + require(!ended, "auctionEnd has already been called."); + + // 2. Effects + ended = true; + emit AuctionEnded(highestBidder, highestBid); + + // 3. Interaction + beneficiary.transfer(highestBid); + } + } + +Blind Auction +============= + +The previous open auction is extended to a blind auction +in the following. The advantage of a blind auction is +that there is no time pressure towards the end of +the bidding period. Creating a blind auction on a +transparent computing platform might sound like a +contradiction, but cryptography comes to the rescue. + +During the **bidding period**, a bidder does not +actually send her bid, but only a hashed version of it. +Since it is currently considered practically impossible +to find two (sufficiently long) values whose hash +values are equal, the bidder commits to the bid by that. +After the end of the bidding period, the bidders have +to reveal their bids: They send their values +unencrypted and the contract checks that the hash value +is the same as the one provided during the bidding period. + +Another challenge is how to make the auction +**binding and blind** at the same time: The only way to +prevent the bidder from just not sending the money +after they won the auction is to make her send it +together with the bid. Since value transfers cannot +be blinded in Ethereum, anyone can see the value. + +The following contract solves this problem by +accepting any value that is larger than the highest +bid. Since this can of course only be checked during +the reveal phase, some bids might be **invalid**, and +this is on purpose (it even provides an explicit +flag to place invalid bids with high value transfers): +Bidders can confuse competition by placing several +high or low invalid bids. + + +:: + + pragma solidity >0.4.23 <0.6.0; + + contract BlindAuction { + struct Bid { + bytes32 blindedBid; + uint deposit; + } + + address payable public beneficiary; + uint public biddingEnd; + uint public revealEnd; + bool public ended; + + mapping(address => Bid[]) public bids; + + address public highestBidder; + uint public highestBid; + + // Allowed withdrawals of previous bids + mapping(address => uint) pendingReturns; + + event AuctionEnded(address winner, uint highestBid); + + /// Modifiers are a convenient way to validate inputs to + /// functions. `onlyBefore` is applied to `bid` below: + /// The new function body is the modifier's body where + /// `_` is replaced by the old function body. + modifier onlyBefore(uint _time) { require(now < _time); _; } + modifier onlyAfter(uint _time) { require(now > _time); _; } + + constructor( + uint _biddingTime, + uint _revealTime, + address payable _beneficiary + ) public { + beneficiary = _beneficiary; + biddingEnd = now + _biddingTime; + revealEnd = biddingEnd + _revealTime; + } + + /// Place a blinded bid with `_blindedBid` = + /// keccak256(abi.encodePacked(value, fake, secret)). + /// The sent ether is only refunded if the bid is correctly + /// revealed in the revealing phase. The bid is valid if the + /// ether sent together with the bid is at least "value" and + /// "fake" is not true. Setting "fake" to true and sending + /// not the exact amount are ways to hide the real bid but + /// still make the required deposit. The same address can + /// place multiple bids. + function bid(bytes32 _blindedBid) + public + payable + onlyBefore(biddingEnd) + { + bids[msg.sender].push(Bid({ + blindedBid: _blindedBid, + deposit: msg.value + })); + } + + /// Reveal your blinded bids. You will get a refund for all + /// correctly blinded invalid bids and for all bids except for + /// the totally highest. + function reveal( + uint[] memory _values, + bool[] memory _fake, + bytes32[] memory _secret + ) + public + onlyAfter(biddingEnd) + onlyBefore(revealEnd) + { + uint length = bids[msg.sender].length; + require(_values.length == length); + require(_fake.length == length); + require(_secret.length == length); + + uint refund; + for (uint i = 0; i < length; i++) { + Bid storage bidToCheck = bids[msg.sender][i]; + (uint value, bool fake, bytes32 secret) = + (_values[i], _fake[i], _secret[i]); + if (bidToCheck.blindedBid != keccak256(abi.encodePacked(value, fake, secret))) { + // Bid was not actually revealed. + // Do not refund deposit. + continue; + } + refund += bidToCheck.deposit; + if (!fake && bidToCheck.deposit >= value) { + if (placeBid(msg.sender, value)) + refund -= value; + } + // Make it impossible for the sender to re-claim + // the same deposit. + bidToCheck.blindedBid = bytes32(0); + } + msg.sender.transfer(refund); + } + + // This is an "internal" function which means that it + // can only be called from the contract itself (or from + // derived contracts). + function placeBid(address bidder, uint value) internal + returns (bool success) + { + if (value <= highestBid) { + return false; + } + if (highestBidder != address(0)) { + // Refund the previously highest bidder. + pendingReturns[highestBidder] += highestBid; + } + highestBid = value; + highestBidder = bidder; + return true; + } + + /// Withdraw a bid that was overbid. + function withdraw() public { + uint amount = pendingReturns[msg.sender]; + if (amount > 0) { + // It is important to set this to zero because the recipient + // can call this function again as part of the receiving call + // before `transfer` returns (see the remark above about + // conditions -> effects -> interaction). + pendingReturns[msg.sender] = 0; + + msg.sender.transfer(amount); + } + } + + /// End the auction and send the highest bid + /// to the beneficiary. + function auctionEnd() + public + onlyAfter(revealEnd) + { + require(!ended); + emit AuctionEnded(highestBidder, highestBid); + ended = true; + beneficiary.transfer(highestBid); + } + }
\ No newline at end of file diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 2cc082b4..4635d577 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -77,15 +77,6 @@ otherwise an exception is thrown. Advanced Questions ****************** -How do you get a random number in a contract? (Implement a self-returning gambling contract.) -============================================================================================= - -Getting randomness right is often the crucial part in a crypto project and -most failures result from bad random number generators. - -If you do not want it to be safe, you build something similar to the `coin flipper <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/35_coin_flipper.sol>`_ -but otherwise, rather use a contract that supplies randomness, like the `RANDAO <https://github.com/randao/randao>`_. - Get return value from non-constant function from another contract ================================================================= @@ -94,23 +85,6 @@ The key point is that the calling contract needs to know about the function it i 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>`_. -How do you create 2-dimensional arrays? -======================================= - -See `2D_array.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/55_2D_array.sol>`_. - -Note that filling a 10x10 square of ``uint8`` + contract creation took more than ``800,000`` -gas at the time of this writing. 17x17 took ``2,000,000`` gas. With the limit at -3.14 million... well, there’s a pretty low ceiling for what you can create right -now. - -Note that merely "creating" the array is free, the costs are in filling it. - -Note2: Optimizing storage access can pull the gas costs down considerably, because -32 ``uint8`` values can be stored in a single slot. The problem is that these optimizations -currently do not work across loops and also have a problem with bounds checking. -You might get much better results in the future, though. - How do I initialize a contract with only a specific amount of wei? ================================================================== @@ -178,16 +152,6 @@ does not fit inside this range, it is truncated. These truncations can have above is necessary to avoid certain attacks. -Why are explicit conversions between fixed-size bytes types and integer types failing? -====================================================================================== - -Since version 0.5.0 explicit conversions between fixed-size byte arrays and integers are only allowed, -if both types have the same size. This prevents unexpected behaviour when truncating or padding. -Such conversions are still possible, but intermediate casts are required that make the desired -truncation and padding convention explicit. See :ref:`types-conversion-elementary-types` for a full -explanation and examples. - - Why can number literals not be converted to fixed-size bytes types? =================================================================== diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index e94a9c29..933b0765 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -3,347 +3,7 @@ Solidity by Example ################### .. include:: examples/voting.rst - -.. index:: auction;blind, auction;open, blind auction, open auction - -************* -Blind Auction -************* - -In this section, we will show how easy it is to create a -completely blind auction contract on Ethereum. -We will start with an open auction where everyone -can see the bids that are made and then extend this -contract into a blind auction where it is not -possible to see the actual bid until the bidding -period ends. - -.. _simple_auction: - -Simple Open Auction -=================== - -The general idea of the following simple auction contract -is that everyone can send their bids during -a bidding period. The bids already include sending -money / ether in order to bind the bidders to their -bid. If the highest bid is raised, the previously -highest bidder gets her money back. -After the end of the bidding period, the -contract has to be called manually for the -beneficiary to receive their money - contracts cannot -activate themselves. - -:: - - pragma solidity >=0.4.22 <0.6.0; - - contract SimpleAuction { - // Parameters of the auction. Times are either - // absolute unix timestamps (seconds since 1970-01-01) - // or time periods in seconds. - address payable public beneficiary; - uint public auctionEndTime; - - // Current state of the auction. - address public highestBidder; - uint public highestBid; - - // Allowed withdrawals of previous bids - mapping(address => uint) pendingReturns; - - // Set to true at the end, disallows any change. - // By default initialized to `false`. - bool ended; - - // Events that will be emitted on changes. - event HighestBidIncreased(address bidder, uint amount); - event AuctionEnded(address winner, uint amount); - - // The following is a so-called natspec comment, - // recognizable by the three slashes. - // It will be shown when the user is asked to - // confirm a transaction. - - /// Create a simple auction with `_biddingTime` - /// seconds bidding time on behalf of the - /// beneficiary address `_beneficiary`. - constructor( - uint _biddingTime, - address payable _beneficiary - ) public { - beneficiary = _beneficiary; - auctionEndTime = now + _biddingTime; - } - - /// Bid on the auction with the value sent - /// together with this transaction. - /// The value will only be refunded if the - /// auction is not won. - function bid() public payable { - // No arguments are necessary, all - // information is already part of - // the transaction. The keyword payable - // is required for the function to - // be able to receive Ether. - - // Revert the call if the bidding - // period is over. - require( - now <= auctionEndTime, - "Auction already ended." - ); - - // If the bid is not higher, send the - // money back. - require( - msg.value > highestBid, - "There already is a higher bid." - ); - - if (highestBid != 0) { - // Sending back the money by simply using - // highestBidder.send(highestBid) is a security risk - // because it could execute an untrusted contract. - // It is always safer to let the recipients - // withdraw their money themselves. - pendingReturns[highestBidder] += highestBid; - } - highestBidder = msg.sender; - highestBid = msg.value; - emit HighestBidIncreased(msg.sender, msg.value); - } - - /// Withdraw a bid that was overbid. - function withdraw() public returns (bool) { - uint amount = pendingReturns[msg.sender]; - if (amount > 0) { - // It is important to set this to zero because the recipient - // can call this function again as part of the receiving call - // before `send` returns. - pendingReturns[msg.sender] = 0; - - if (!msg.sender.send(amount)) { - // No need to call throw here, just reset the amount owing - pendingReturns[msg.sender] = amount; - return false; - } - } - return true; - } - - /// End the auction and send the highest bid - /// to the beneficiary. - function auctionEnd() public { - // It is a good guideline to structure functions that interact - // with other contracts (i.e. they call functions or send Ether) - // into three phases: - // 1. checking conditions - // 2. performing actions (potentially changing conditions) - // 3. interacting with other contracts - // If these phases are mixed up, the other contract could call - // back into the current contract and modify the state or cause - // effects (ether payout) to be performed multiple times. - // If functions called internally include interaction with external - // contracts, they also have to be considered interaction with - // external contracts. - - // 1. Conditions - require(now >= auctionEndTime, "Auction not yet ended."); - require(!ended, "auctionEnd has already been called."); - - // 2. Effects - ended = true; - emit AuctionEnded(highestBidder, highestBid); - - // 3. Interaction - beneficiary.transfer(highestBid); - } - } - -Blind Auction -============= - -The previous open auction is extended to a blind auction -in the following. The advantage of a blind auction is -that there is no time pressure towards the end of -the bidding period. Creating a blind auction on a -transparent computing platform might sound like a -contradiction, but cryptography comes to the rescue. - -During the **bidding period**, a bidder does not -actually send her bid, but only a hashed version of it. -Since it is currently considered practically impossible -to find two (sufficiently long) values whose hash -values are equal, the bidder commits to the bid by that. -After the end of the bidding period, the bidders have -to reveal their bids: They send their values -unencrypted and the contract checks that the hash value -is the same as the one provided during the bidding period. - -Another challenge is how to make the auction -**binding and blind** at the same time: The only way to -prevent the bidder from just not sending the money -after they won the auction is to make her send it -together with the bid. Since value transfers cannot -be blinded in Ethereum, anyone can see the value. - -The following contract solves this problem by -accepting any value that is larger than the highest -bid. Since this can of course only be checked during -the reveal phase, some bids might be **invalid**, and -this is on purpose (it even provides an explicit -flag to place invalid bids with high value transfers): -Bidders can confuse competition by placing several -high or low invalid bids. - - -:: - - pragma solidity >0.4.23 <0.6.0; - - contract BlindAuction { - struct Bid { - bytes32 blindedBid; - uint deposit; - } - - address payable public beneficiary; - uint public biddingEnd; - uint public revealEnd; - bool public ended; - - mapping(address => Bid[]) public bids; - - address public highestBidder; - uint public highestBid; - - // Allowed withdrawals of previous bids - mapping(address => uint) pendingReturns; - - event AuctionEnded(address winner, uint highestBid); - - /// Modifiers are a convenient way to validate inputs to - /// functions. `onlyBefore` is applied to `bid` below: - /// The new function body is the modifier's body where - /// `_` is replaced by the old function body. - modifier onlyBefore(uint _time) { require(now < _time); _; } - modifier onlyAfter(uint _time) { require(now > _time); _; } - - constructor( - uint _biddingTime, - uint _revealTime, - address payable _beneficiary - ) public { - beneficiary = _beneficiary; - biddingEnd = now + _biddingTime; - revealEnd = biddingEnd + _revealTime; - } - - /// Place a blinded bid with `_blindedBid` = - /// keccak256(abi.encodePacked(value, fake, secret)). - /// The sent ether is only refunded if the bid is correctly - /// revealed in the revealing phase. The bid is valid if the - /// ether sent together with the bid is at least "value" and - /// "fake" is not true. Setting "fake" to true and sending - /// not the exact amount are ways to hide the real bid but - /// still make the required deposit. The same address can - /// place multiple bids. - function bid(bytes32 _blindedBid) - public - payable - onlyBefore(biddingEnd) - { - bids[msg.sender].push(Bid({ - blindedBid: _blindedBid, - deposit: msg.value - })); - } - - /// Reveal your blinded bids. You will get a refund for all - /// correctly blinded invalid bids and for all bids except for - /// the totally highest. - function reveal( - uint[] memory _values, - bool[] memory _fake, - bytes32[] memory _secret - ) - public - onlyAfter(biddingEnd) - onlyBefore(revealEnd) - { - uint length = bids[msg.sender].length; - require(_values.length == length); - require(_fake.length == length); - require(_secret.length == length); - - uint refund; - for (uint i = 0; i < length; i++) { - Bid storage bidToCheck = bids[msg.sender][i]; - (uint value, bool fake, bytes32 secret) = - (_values[i], _fake[i], _secret[i]); - if (bidToCheck.blindedBid != keccak256(abi.encodePacked(value, fake, secret))) { - // Bid was not actually revealed. - // Do not refund deposit. - continue; - } - refund += bidToCheck.deposit; - if (!fake && bidToCheck.deposit >= value) { - if (placeBid(msg.sender, value)) - refund -= value; - } - // Make it impossible for the sender to re-claim - // the same deposit. - bidToCheck.blindedBid = bytes32(0); - } - msg.sender.transfer(refund); - } - - // This is an "internal" function which means that it - // can only be called from the contract itself (or from - // derived contracts). - function placeBid(address bidder, uint value) internal - returns (bool success) - { - if (value <= highestBid) { - return false; - } - if (highestBidder != address(0)) { - // Refund the previously highest bidder. - pendingReturns[highestBidder] += highestBid; - } - highestBid = value; - highestBidder = bidder; - return true; - } - - /// Withdraw a bid that was overbid. - function withdraw() public { - uint amount = pendingReturns[msg.sender]; - if (amount > 0) { - // It is important to set this to zero because the recipient - // can call this function again as part of the receiving call - // before `transfer` returns (see the remark above about - // conditions -> effects -> interaction). - pendingReturns[msg.sender] = 0; - - msg.sender.transfer(amount); - } - } - - /// End the auction and send the highest bid - /// to the beneficiary. - function auctionEnd() - public - onlyAfter(revealEnd) - { - require(!ended); - emit AuctionEnded(highestBidder, highestBid); - ended = true; - beneficiary.transfer(highestBid); - } - } - +.. include:: examples/blind-auction.rst .. include:: examples/safe-remote.rst diff --git a/docs/types.rst b/docs/types.rst index ea45b7d7..b9c06f6c 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -22,191 +22,8 @@ tuple with a second `bool` value denoting success. .. include:: types/reference-types.rst -.. index:: !mapping -.. _mapping-types: - -Mapping Types -============= - -You declare mapping types with the syntax ``mapping(_KeyType => _ValueType)``. -The ``_KeyType`` can be any elementary type. This means it can be any of -the built-in value types plus ``bytes`` and ``string``. User-defined -or complex types like contract types, enums, mappings, structs and any array type -apart from ``bytes`` and ``string`` are not allowed. -``_ValueType`` can be any type, including mappings. - -You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised -such that every possible key exists and is mapped to a value whose -byte-representation is all zeros, a type's :ref:`default value <default-value>`. The similarity ends there, the key data is not stored in a -mapping, only its ``keccak256`` hash is used to look up the value. - -Because of this, mappings do not have a length or a concept of a key or -value being set. - -Mappings can only have a data location of ``storage`` and thus -are allowed for state variables, as storage reference types -in functions, or as parameters for library functions. -They cannot be used as parameters or return parameters -of contract functions that are publicly visible. - -You can mark variables of mapping type as ``public`` and Solidity creates a -:ref:`getter <visibility-and-getters>` for you. The ``_KeyType`` becomes a -parameter for the getter. If ``_ValueType`` is a value type or a struct, -the getter returns ``_ValueType``. -If ``_ValueType`` is an array or a mapping, the getter has one parameter for -each ``_KeyType``, recursively. For example with a mapping: - -:: - - pragma solidity >=0.4.0 <0.6.0; - - contract MappingExample { - mapping(address => uint) public balances; - - function update(uint newBalance) public { - balances[msg.sender] = newBalance; - } - } - - contract MappingUser { - function f() public returns (uint) { - MappingExample m = new MappingExample(); - m.update(100); - return m.balances(address(this)); - } - } - - -.. note:: - Mappings are not iterable, but it is possible to implement a data structure - on top of them. For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_. +.. include:: types/mapping-types.rst .. include:: types/operators.rst -.. index:: ! type;conversion, ! cast - -.. _types-conversion-elementary-types: - -Conversions between Elementary Types -==================================== - -Implicit Conversions --------------------- - -If an operator is applied to different types, the compiler tries to -implicitly convert one of the operands to the type of the other (the same is -true for assignments). In general, an implicit conversion between value-types -is possible if it -makes sense semantically and no information is lost: ``uint8`` is convertible to -``uint16`` and ``int128`` to ``int256``, but ``int8`` is not convertible to ``uint256`` -(because ``uint256`` cannot hold e.g. ``-1``). - -For more details, please consult the sections about the types themselves. - -Explicit Conversions --------------------- - -If the compiler does not allow implicit conversion but you know what you are -doing, an explicit type conversion is sometimes possible. Note that this may -give you some unexpected behaviour and allows you to bypass some security -features of the compiler, so be sure to test that the -result is what you want! Take the following example where you are converting -a negative ``int8`` to a ``uint``: - -:: - - int8 y = -3; - uint x = uint(y); - -At the end of this code snippet, ``x`` will have the value ``0xfffff..fd`` (64 hex -characters), which is -3 in the two's complement representation of 256 bits. - -If an integer is explicitly converted to a smaller type, higher-order bits are -cut off:: - - uint32 a = 0x12345678; - uint16 b = uint16(a); // b will be 0x5678 now - -If an integer is explicitly converted to a larger type, it is padded on the left (i.e. at the higher order end). -The result of the conversion will compare equal to the original integer:: - - uint16 a = 0x1234; - uint32 b = uint32(a); // b will be 0x00001234 now - assert(a == b); - -Fixed-size bytes types behave differently during conversions. They can be thought of as -sequences of individual bytes and converting to a smaller type will cut off the -sequence:: - - bytes2 a = 0x1234; - bytes1 b = bytes1(a); // b will be 0x12 - -If a fixed-size bytes type is explicitly converted to a larger type, it is padded on -the right. Accessing the byte at a fixed index will result in the same value before and -after the conversion (if the index is still in range):: - - bytes2 a = 0x1234; - bytes4 b = bytes4(a); // b will be 0x12340000 - assert(a[0] == b[0]); - assert(a[1] == b[1]); - -Since integers and fixed-size byte arrays behave differently when truncating or -padding, explicit conversions between integers and fixed-size byte arrays are only allowed, -if both have the same size. If you want to convert between integers and fixed-size byte arrays of -different size, you have to use intermediate conversions that make the desired truncation and padding -rules explicit:: - - bytes2 a = 0x1234; - uint32 b = uint16(a); // b will be 0x00001234 - uint32 c = uint32(bytes4(a)); // c will be 0x12340000 - uint8 d = uint8(uint16(a)); // d will be 0x34 - uint8 e = uint8(bytes1(a)); // e will be 0x12 - -.. _types-conversion-literals: - -Conversions between Literals and Elementary Types -================================================= - -Integer Types -------------- - -Decimal and hexadecimal number literals can be implicitly converted to any integer type -that is large enough to represent it without truncation:: - - uint8 a = 12; // fine - uint32 b = 1234; // fine - uint16 c = 0x123456; // fails, since it would have to truncate to 0x3456 - -Fixed-Size Byte Arrays ----------------------- - -Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal -number literals can be, but only if the number of hex digits exactly fits the size of the bytes -type. As an exception both decimal and hexadecimal literals which have a value of zero can be -converted to any fixed-size bytes type:: - - bytes2 a = 54321; // not allowed - bytes2 b = 0x12; // not allowed - bytes2 c = 0x123; // not allowed - bytes2 d = 0x1234; // fine - bytes2 e = 0x0012; // fine - bytes4 f = 0; // fine - bytes4 g = 0x0; // fine - -String literals and hex string literals can be implicitly converted to fixed-size byte arrays, -if their number of characters matches the size of the bytes type:: - - bytes2 a = hex"1234"; // fine - bytes2 b = "xy"; // fine - bytes2 c = hex"12"; // not allowed - bytes2 d = hex"123"; // not allowed - bytes2 e = "x"; // not allowed - bytes2 f = "xyz"; // not allowed - -Addresses ---------- - -As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum -test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type. - -Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``. +.. include:: types/conversion.rst
\ No newline at end of file diff --git a/docs/types/conversion.rst b/docs/types/conversion.rst new file mode 100644 index 00000000..5a9f84c0 --- /dev/null +++ b/docs/types/conversion.rst @@ -0,0 +1,127 @@ +.. index:: ! type;conversion, ! cast + +.. _types-conversion-elementary-types: + +Conversions between Elementary Types +==================================== + +Implicit Conversions +-------------------- + +If an operator is applied to different types, the compiler tries to +implicitly convert one of the operands to the type of the other (the same is +true for assignments). In general, an implicit conversion between value-types +is possible if it +makes sense semantically and no information is lost: ``uint8`` is convertible to +``uint16`` and ``int128`` to ``int256``, but ``int8`` is not convertible to ``uint256`` +(because ``uint256`` cannot hold e.g. ``-1``). + +For more details, please consult the sections about the types themselves. + +Explicit Conversions +-------------------- + +If the compiler does not allow implicit conversion but you know what you are +doing, an explicit type conversion is sometimes possible. Note that this may +give you some unexpected behaviour and allows you to bypass some security +features of the compiler, so be sure to test that the +result is what you want! Take the following example where you are converting +a negative ``int8`` to a ``uint``: + +:: + + int8 y = -3; + uint x = uint(y); + +At the end of this code snippet, ``x`` will have the value ``0xfffff..fd`` (64 hex +characters), which is -3 in the two's complement representation of 256 bits. + +If an integer is explicitly converted to a smaller type, higher-order bits are +cut off:: + + uint32 a = 0x12345678; + uint16 b = uint16(a); // b will be 0x5678 now + +If an integer is explicitly converted to a larger type, it is padded on the left (i.e. at the higher order end). +The result of the conversion will compare equal to the original integer:: + + uint16 a = 0x1234; + uint32 b = uint32(a); // b will be 0x00001234 now + assert(a == b); + +Fixed-size bytes types behave differently during conversions. They can be thought of as +sequences of individual bytes and converting to a smaller type will cut off the +sequence:: + + bytes2 a = 0x1234; + bytes1 b = bytes1(a); // b will be 0x12 + +If a fixed-size bytes type is explicitly converted to a larger type, it is padded on +the right. Accessing the byte at a fixed index will result in the same value before and +after the conversion (if the index is still in range):: + + bytes2 a = 0x1234; + bytes4 b = bytes4(a); // b will be 0x12340000 + assert(a[0] == b[0]); + assert(a[1] == b[1]); + +Since integers and fixed-size byte arrays behave differently when truncating or +padding, explicit conversions between integers and fixed-size byte arrays are only allowed, +if both have the same size. If you want to convert between integers and fixed-size byte arrays of +different size, you have to use intermediate conversions that make the desired truncation and padding +rules explicit:: + + bytes2 a = 0x1234; + uint32 b = uint16(a); // b will be 0x00001234 + uint32 c = uint32(bytes4(a)); // c will be 0x12340000 + uint8 d = uint8(uint16(a)); // d will be 0x34 + uint8 e = uint8(bytes1(a)); // e will be 0x12 + +.. _types-conversion-literals: + +Conversions between Literals and Elementary Types +================================================= + +Integer Types +------------- + +Decimal and hexadecimal number literals can be implicitly converted to any integer type +that is large enough to represent it without truncation:: + + uint8 a = 12; // fine + uint32 b = 1234; // fine + uint16 c = 0x123456; // fails, since it would have to truncate to 0x3456 + +Fixed-Size Byte Arrays +---------------------- + +Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal +number literals can be, but only if the number of hex digits exactly fits the size of the bytes +type. As an exception both decimal and hexadecimal literals which have a value of zero can be +converted to any fixed-size bytes type:: + + bytes2 a = 54321; // not allowed + bytes2 b = 0x12; // not allowed + bytes2 c = 0x123; // not allowed + bytes2 d = 0x1234; // fine + bytes2 e = 0x0012; // fine + bytes4 f = 0; // fine + bytes4 g = 0x0; // fine + +String literals and hex string literals can be implicitly converted to fixed-size byte arrays, +if their number of characters matches the size of the bytes type:: + + bytes2 a = hex"1234"; // fine + bytes2 b = "xy"; // fine + bytes2 c = hex"12"; // not allowed + bytes2 d = hex"123"; // not allowed + bytes2 e = "x"; // not allowed + bytes2 f = "xyz"; // not allowed + +Addresses +--------- + +As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum +test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type. + +Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``. diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst new file mode 100644 index 00000000..935ed6b4 --- /dev/null +++ b/docs/types/mapping-types.rst @@ -0,0 +1,58 @@ +.. index:: !mapping +.. _mapping-types: + +Mapping Types +============= + +You declare mapping types with the syntax ``mapping(_KeyType => _ValueType)``. +The ``_KeyType`` can be any elementary type. This means it can be any of +the built-in value types plus ``bytes`` and ``string``. User-defined +or complex types like contract types, enums, mappings, structs and any array type +apart from ``bytes`` and ``string`` are not allowed. +``_ValueType`` can be any type, including mappings. + +You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised +such that every possible key exists and is mapped to a value whose +byte-representation is all zeros, a type's :ref:`default value <default-value>`. The similarity ends there, the key data is not stored in a +mapping, only its ``keccak256`` hash is used to look up the value. + +Because of this, mappings do not have a length or a concept of a key or +value being set. + +Mappings can only have a data location of ``storage`` and thus +are allowed for state variables, as storage reference types +in functions, or as parameters for library functions. +They cannot be used as parameters or return parameters +of contract functions that are publicly visible. + +You can mark variables of mapping type as ``public`` and Solidity creates a +:ref:`getter <visibility-and-getters>` for you. The ``_KeyType`` becomes a +parameter for the getter. If ``_ValueType`` is a value type or a struct, +the getter returns ``_ValueType``. +If ``_ValueType`` is an array or a mapping, the getter has one parameter for +each ``_KeyType``, recursively. For example with a mapping: + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract MappingExample { + mapping(address => uint) public balances; + + function update(uint newBalance) public { + balances[msg.sender] = newBalance; + } + } + + contract MappingUser { + function f() public returns (uint) { + MappingExample m = new MappingExample(); + m.update(100); + return m.balances(address(this)); + } + } + + +.. note:: + Mappings are not iterable, but it is possible to implement a data structure + on top of them. For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_. |