diff options
Diffstat (limited to 'docs/contracts')
-rw-r--r-- | docs/contracts/abstract-contracts.rst | 43 | ||||
-rw-r--r-- | docs/contracts/constant-state-variables.rst | 35 | ||||
-rw-r--r-- | docs/contracts/creating-contracts.rst | 117 | ||||
-rw-r--r-- | docs/contracts/events.rst | 161 | ||||
-rw-r--r-- | docs/contracts/function-modifiers.rst | 111 | ||||
-rw-r--r-- | docs/contracts/functions.rst | 398 | ||||
-rw-r--r-- | docs/contracts/inheritance.rst | 299 | ||||
-rw-r--r-- | docs/contracts/interfaces.rst | 36 | ||||
-rw-r--r-- | docs/contracts/libraries.rst | 230 | ||||
-rw-r--r-- | docs/contracts/using-for.rst | 119 | ||||
-rw-r--r-- | docs/contracts/visibility-and-getters.rst | 198 |
11 files changed, 1747 insertions, 0 deletions
diff --git a/docs/contracts/abstract-contracts.rst b/docs/contracts/abstract-contracts.rst new file mode 100644 index 00000000..87340733 --- /dev/null +++ b/docs/contracts/abstract-contracts.rst @@ -0,0 +1,43 @@ +.. index:: ! contract;abstract, ! abstract contract + +.. _abstract-contract: + +****************** +Abstract Contracts +****************** + +Contracts are marked as abstract when at least one of their functions lacks an implementation as in the following example (note that the function declaration header is terminated by ``;``):: + + pragma solidity >=0.4.0 <0.6.0; + + contract Feline { + function utterance() public returns (bytes32); + } + +Such contracts cannot be compiled (even if they contain implemented functions alongside non-implemented functions), but they can be used as base contracts:: + + pragma solidity >=0.4.0 <0.6.0; + + contract Feline { + function utterance() public returns (bytes32); + } + + contract Cat is Feline { + function utterance() public returns (bytes32) { return "miaow"; } + } + +If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it will itself be abstract. + +Note that a function without implementation is different from a :ref:`Function Type <function_types>` even though their syntax looks very similar. + +Example of function without implementation (a function declaration):: + + function foo(address) external returns (address); + +Example of a Function Type (a variable declaration, where the variable is of type ``function``):: + + function(address) external returns (address) foo; + +Abstract contracts decouple the definition of a contract from its implementation providing better extensibility and self-documentation and +facilitating patterns like the `Template method <https://en.wikipedia.org/wiki/Template_method_pattern>`_ and removing code duplication. +Abstract contracts are useful in the same way that defining methods in an interface is useful. It is a way for the designer of the abstract contract to say "any child of mine must implement this method". diff --git a/docs/contracts/constant-state-variables.rst b/docs/contracts/constant-state-variables.rst new file mode 100644 index 00000000..3e615ed0 --- /dev/null +++ b/docs/contracts/constant-state-variables.rst @@ -0,0 +1,35 @@ +.. index:: ! constant + +************************ +Constant State Variables +************************ + +State variables can be declared as ``constant``. In this case, they have to be +assigned from an expression which is a constant at compile time. Any expression +that accesses storage, blockchain data (e.g. ``now``, ``address(this).balance`` or +``block.number``) or +execution data (``msg.value`` or ``gasleft()``) or makes calls to external contracts is disallowed. Expressions +that might have a side-effect on memory allocation are allowed, but those that +might have a side-effect on other memory objects are not. The built-in functions +``keccak256``, ``sha256``, ``ripemd160``, ``ecrecover``, ``addmod`` and ``mulmod`` +are allowed (even though, with the exception of ``keccak256``, they do call external contracts). + +The reason behind allowing side-effects on the memory allocator is that it +should be possible to construct complex objects like e.g. lookup-tables. +This feature is not yet fully usable. + +The compiler does not reserve a storage slot for these variables, and every occurrence is +replaced by the respective constant expression (which might be computed to a single value by the optimizer). + +Not all types for constants are implemented at this time. The only supported types are +value types and strings. + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract C { + uint constant x = 32**22 + 8; + string constant text = "abc"; + bytes32 constant myHash = keccak256("abc"); + } diff --git a/docs/contracts/creating-contracts.rst b/docs/contracts/creating-contracts.rst new file mode 100644 index 00000000..981243b1 --- /dev/null +++ b/docs/contracts/creating-contracts.rst @@ -0,0 +1,117 @@ +.. index:: ! contract;creation, constructor + +****************** +Creating Contracts +****************** + +Contracts can be created "from outside" via Ethereum transactions or from within Solidity contracts. + +IDEs, such as `Remix <https://remix.ethereum.org/>`_, make the creation process seamless using UI elements. + +Creating contracts programmatically on Ethereum is best done via using the JavaScript API `web3.js <https://github.com/ethereum/web3.js>`_. +It has a function called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_ +to facilitate contract creation. + +When a contract is created, its :ref:`constructor <constructor>` (a function declared with the ``constructor`` keyword) is executed once. + +A constructor is optional. Only one constructor is allowed, which means +overloading is not supported. + +After the constructor has executed, the final code of the contract is deployed to the +blockchain. This code includes all public and external functions and all functions +that are reachable from there through function calls. The deployed code does not +include the constructor code or internal functions only called from the constructor. + +.. index:: constructor;arguments + +Internally, constructor arguments are passed :ref:`ABI encoded <ABI>` after the code of +the contract itself, but you do not have to care about this if you use ``web3.js``. + +If a contract wants to create another contract, the source code +(and the binary) of the created contract has to be known to the creator. +This means that cyclic creation dependencies are impossible. + +:: + + pragma solidity >=0.4.22 <0.6.0; + + contract OwnedToken { + // `TokenCreator` is a contract type that is defined below. + // It is fine to reference it as long as it is not used + // to create a new contract. + TokenCreator creator; + address owner; + bytes32 name; + + // This is the constructor which registers the + // creator and the assigned name. + constructor(bytes32 _name) public { + // State variables are accessed via their name + // and not via e.g. `this.owner`. Functions can + // be accessed directly or through `this.f`, + // but the latter provides an external view + // to the function. Especially in the constructor, + // you should not access functions externally, + // because the function does not exist yet. + // See the next section for details. + owner = msg.sender; + + // We do an explicit type conversion from `address` + // to `TokenCreator` and assume that the type of + // the calling contract is `TokenCreator`, there is + // no real way to check that. + creator = TokenCreator(msg.sender); + name = _name; + } + + function changeName(bytes32 newName) public { + // Only the creator can alter the name -- + // the comparison is possible since contracts + // are explicitly convertible to addresses. + if (msg.sender == address(creator)) + name = newName; + } + + function transfer(address newOwner) public { + // Only the current owner can transfer the token. + if (msg.sender != owner) return; + + // We ask the creator contract if the transfer + // should proceed by using a function of the + // `TokenCreator` contract defined below. If + // the call fails (e.g. due to out-of-gas), + // the execution also fails here. + if (creator.isTokenTransferOK(owner, newOwner)) + owner = newOwner; + } + } + + contract TokenCreator { + function createToken(bytes32 name) + public + returns (OwnedToken tokenAddress) + { + // Create a new `Token` contract and return its address. + // From the JavaScript side, the return type is + // `address`, as this is the closest type available in + // the ABI. + return new OwnedToken(name); + } + + function changeName(OwnedToken tokenAddress, bytes32 name) public { + // Again, the external type of `tokenAddress` is + // simply `address`. + tokenAddress.changeName(name); + } + + // Perform checks to determine if transferring a token to the + // `OwnedToken` contract should proceed + function isTokenTransferOK(address currentOwner, address newOwner) + public + pure + returns (bool ok) + { + // Check an arbitrary condition to see if transfer should proceed + return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f; + } + } diff --git a/docs/contracts/events.rst b/docs/contracts/events.rst new file mode 100644 index 00000000..ecb0a87f --- /dev/null +++ b/docs/contracts/events.rst @@ -0,0 +1,161 @@ +.. index:: ! event + +.. _events: + +****** +Events +****** + +Solidity events give an abstraction on top of the EVM's logging functionality. +Applications can subscribe and listen to these events through the RPC interface of an Ethereum client. + +Events are inheritable members of contracts. When you call them, they cause the +arguments to be stored in the transaction's log - a special data structure +in the blockchain. These logs are associated with the address of the contract, +are incorporated into the blockchain, and stay there as long as a block is +accessible (forever as of the Frontier and Homestead releases, but this might +change with Serenity). The Log and its event data is not accessible from within +contracts (not even from the contract that created them). + +It is possible to request a simple payment verification (SPV) for logs, so if +an external entity supplies a contract with such a verification, it can check +that the log actually exists inside the blockchain. You have to supply block headers +because the contract can only see the last 256 block hashes. + +You can add the attribute ``indexed`` to up to three parameters which adds them +to a special data structure known as :ref:`"topics" <abi_events>` instead of +the data part of the log. If you use arrays (including ``string`` and ``bytes``) +as indexed arguments, its Keccak-256 hash is stored as a topic instead, this is +because a topic can only hold a single word (32 bytes). + +All parameters without the ``indexed`` attribute are :ref:`ABI-encoded <ABI>` +into the data part of the log. + +Topics allow you to search for events, for example when filtering a sequence of +blocks for certain events. You can also filter events by the address of the +contract that emitted the event. + +For example, the code below uses the web3.js ``subscribe("logs")`` +`method <https://web3js.readthedocs.io/en/1.0/web3-eth-subscribe.html#subscribe-logs>`_ to filter +logs that match a topic with a certain address value: + +.. code-block:: javascript + + var options = { + fromBlock: 0, + address: web3.eth.defaultAccount, + topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null] + }; + web3.eth.subscribe('logs', options, function (error, result) { + if (!error) + console.log(result); + }) + .on("data", function (log) { + console.log(log); + }) + .on("changed", function (log) { + }); + + +The hash of the signature of the event is one of the topics, except if you +declared the event with the ``anonymous`` specifier. This means that it is +not possible to filter for specific anonymous events by name. + +:: + + pragma solidity >=0.4.21 <0.6.0; + + contract ClientReceipt { + event Deposit( + address indexed _from, + bytes32 indexed _id, + uint _value + ); + + function deposit(bytes32 _id) public payable { + // Events are emitted using `emit`, followed by + // the name of the event and the arguments + // (if any) in parentheses. Any such invocation + // (even deeply nested) can be detected from + // the JavaScript API by filtering for `Deposit`. + emit Deposit(msg.sender, _id, msg.value); + } + } + +The use in the JavaScript API is as follows: + +:: + + var abi = /* abi as generated by the compiler */; + var ClientReceipt = web3.eth.contract(abi); + var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */); + + var event = clientReceipt.Deposit(); + + // watch for changes + event.watch(function(error, result){ + // result contains non-indexed arguments and topics + // given to the `Deposit` call. + if (!error) + console.log(result); + }); + + + // Or pass a callback to start watching immediately + var event = clientReceipt.Deposit(function(error, result) { + if (!error) + console.log(result); + }); + +The output of the above looks like the following (trimmed): + +.. code-block:: json + + { + "returnValues": { + "_from": "0x1111…FFFFCCCC", + "_id": "0x50…sd5adb20", + "_value": "0x420042" + }, + "raw": { + "data": "0x7f…91385", + "topics": ["0xfd4…b4ead7", "0x7f…1a91385"] + } + } + +.. index:: ! log + +Low-Level Interface to Logs +=========================== + +It is also possible to access the low-level interface to the logging +mechanism via the functions ``log0``, ``log1``, ``log2``, ``log3`` and ``log4``. +``logi`` takes ``i + 1`` parameter of type ``bytes32``, where the first +argument will be used for the data part of the log and the others +as topics. The event call above can be performed in the same way as + +:: + + pragma solidity >=0.4.10 <0.6.0; + + contract C { + function f() public payable { + uint256 _id = 0x420042; + log3( + bytes32(msg.value), + bytes32(0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20), + bytes32(uint256(msg.sender)), + bytes32(_id) + ); + } + } + +where the long hexadecimal number is equal to +``keccak256("Deposit(address,bytes32,uint256)")``, the signature of the event. + +Additional Resources for Understanding Events +============================================== + +- `Javascript documentation <https://github.com/ethereum/wiki/wiki/JavaScript-API#contract-events>`_ +- `Example usage of events <https://github.com/debris/smart-exchange/blob/master/lib/contracts/SmartExchange.sol>`_ +- `How to access them in js <https://github.com/debris/smart-exchange/blob/master/lib/exchange_transactions.js>`_ diff --git a/docs/contracts/function-modifiers.rst b/docs/contracts/function-modifiers.rst new file mode 100644 index 00000000..376cd9fa --- /dev/null +++ b/docs/contracts/function-modifiers.rst @@ -0,0 +1,111 @@ +.. index:: ! function;modifier + +.. _modifiers: + +****************** +Function Modifiers +****************** + +Modifiers can be used to easily change the behaviour of functions. For example, +they can automatically check a condition prior to executing the function. Modifiers are +inheritable properties of contracts and may be overridden by derived contracts. + +:: + + pragma solidity ^0.5.0; + + contract owned { + constructor() public { owner = msg.sender; } + address payable owner; + + // This contract only defines a modifier but does not use + // it: it will be used in derived contracts. + // The function body is inserted where the special symbol + // `_;` in the definition of a modifier appears. + // This means that if the owner calls this function, the + // function is executed and otherwise, an exception is + // thrown. + modifier onlyOwner { + require( + msg.sender == owner, + "Only owner can call this function." + ); + _; + } + } + + contract mortal is owned { + // This contract inherits the `onlyOwner` modifier from + // `owned` and applies it to the `close` function, which + // causes that calls to `close` only have an effect if + // they are made by the stored owner. + function close() public onlyOwner { + selfdestruct(owner); + } + } + + contract priced { + // Modifiers can receive arguments: + modifier costs(uint price) { + if (msg.value >= price) { + _; + } + } + } + + contract Register is priced, owned { + mapping (address => bool) registeredAddresses; + uint price; + + constructor(uint initialPrice) public { price = initialPrice; } + + // It is important to also provide the + // `payable` keyword here, otherwise the function will + // automatically reject all Ether sent to it. + function register() public payable costs(price) { + registeredAddresses[msg.sender] = true; + } + + function changePrice(uint _price) public onlyOwner { + price = _price; + } + } + + contract Mutex { + bool locked; + modifier noReentrancy() { + require( + !locked, + "Reentrant call." + ); + locked = true; + _; + locked = false; + } + + /// This function is protected by a mutex, which means that + /// reentrant calls from within `msg.sender.call` cannot call `f` again. + /// The `return 7` statement assigns 7 to the return value but still + /// executes the statement `locked = false` in the modifier. + function f() public noReentrancy returns (uint) { + (bool success,) = msg.sender.call(""); + require(success); + return 7; + } + } + +Multiple modifiers are applied to a function by specifying them in a +whitespace-separated list and are evaluated in the order presented. + +.. warning:: + In an earlier version of Solidity, ``return`` statements in functions + having modifiers behaved differently. + +Explicit returns from a modifier or function body only leave the current +modifier or function body. Return variables are assigned and +control flow continues after the "_" in the preceding modifier. + +Arbitrary expressions are allowed for modifier arguments and in this context, +all symbols visible from the function are visible in the modifier. Symbols +introduced in the modifier are not visible in the function (as they might +change by overriding). diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst new file mode 100644 index 00000000..522ce5c4 --- /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). To receive Ether and add it to the total balance of the contract, the fallback function +must be marked ``payable``. If no such function exists, the contract cannot receive +Ether through regular transactions and throws an exception. + +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/contracts/inheritance.rst b/docs/contracts/inheritance.rst new file mode 100644 index 00000000..2e94c2f9 --- /dev/null +++ b/docs/contracts/inheritance.rst @@ -0,0 +1,299 @@ +.. index:: ! inheritance, ! base class, ! contract;base, ! deriving + +*********** +Inheritance +*********** + +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 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 compiled into the created contract. + +The general inheritance system is very similar to +`Python's <https://docs.python.org/3/tutorial/classes.html#inheritance>`_, +especially concerning multiple inheritance, but there are also +some :ref:`differences <multi-inheritance>`. + +Details are given in the following example. + +:: + + pragma solidity ^0.5.0; + + contract owned { + constructor() public { owner = msg.sender; } + address payable owner; + } + + // Use `is` to derive from another contract. Derived + // contracts can access all non-private members including + // internal functions and state variables. These cannot be + // accessed externally via `this`, though. + contract mortal is owned { + function kill() public { + if (msg.sender == owner) selfdestruct(owner); + } + } + + // These abstract contracts are only provided to make the + // interface known to the compiler. Note the function + // without body. If a contract does not implement all + // functions it can only be used as an interface. + contract Config { + function lookup(uint id) public returns (address adr); + } + + contract NameReg { + function register(bytes32 name) public; + function unregister() public; + } + + // Multiple inheritance is possible. Note that `owned` is + // also a base class of `mortal`, yet there is only a single + // instance of `owned` (as for virtual inheritance in C++). + contract named is owned, mortal { + constructor(bytes32 name) public { + Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); + NameReg(config.lookup(1)).register(name); + } + + // Functions can be overridden by another function with the same name and + // the same number/types of inputs. If the overriding function has different + // types of output parameters, that causes an error. + // Both local and message-based function calls take these overrides + // into account. + function kill() public { + if (msg.sender == owner) { + Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); + NameReg(config.lookup(1)).unregister(); + // It is still possible to call a specific + // overridden function. + mortal.kill(); + } + } + } + + // If a constructor takes an argument, it needs to be + // provided in the header (or modifier-invocation-style at + // the constructor of the derived contract (see below)). + contract PriceFeed is owned, mortal, named("GoldFeed") { + function updateInfo(uint newInfo) public { + if (msg.sender == owner) info = newInfo; + } + + function get() public view returns(uint r) { return info; } + + uint info; + } + +Note that above, we call ``mortal.kill()`` to "forward" the +destruction request. The way this is done is problematic, as +seen in the following example:: + + pragma solidity >=0.4.22 <0.6.0; + + contract owned { + constructor() public { owner = msg.sender; } + address payable owner; + } + + contract mortal is owned { + function kill() public { + if (msg.sender == owner) selfdestruct(owner); + } + } + + contract Base1 is mortal { + function kill() public { /* do cleanup 1 */ mortal.kill(); } + } + + contract Base2 is mortal { + function kill() public { /* do cleanup 2 */ mortal.kill(); } + } + + contract Final is Base1, Base2 { + } + +A call to ``Final.kill()`` will call ``Base2.kill`` as the most +derived override, but this function will bypass +``Base1.kill``, basically because it does not even know about +``Base1``. The way around this is to use ``super``:: + + pragma solidity >=0.4.22 <0.6.0; + + contract owned { + constructor() public { owner = msg.sender; } + address payable owner; + } + + contract mortal is owned { + function kill() public { + if (msg.sender == owner) selfdestruct(owner); + } + } + + contract Base1 is mortal { + function kill() public { /* do cleanup 1 */ super.kill(); } + } + + + contract Base2 is mortal { + function kill() public { /* do cleanup 2 */ super.kill(); } + } + + contract Final is Base1, Base2 { + } + +If ``Base2`` calls a function of ``super``, it does not simply +call this function on one of its base contracts. Rather, it +calls this function on the next base contract in the final +inheritance graph, so it will call ``Base1.kill()`` (note that +the final inheritance sequence is -- starting with the most +derived contract: Final, Base2, Base1, mortal, owned). +The actual function that is called when using super is +not known in the context of the class where it is used, +although its type is known. This is similar for ordinary +virtual method lookup. + +.. index:: ! constructor + +.. _constructor: + +Constructors +============ + +A constructor is an optional function declared with the ``constructor`` keyword +which is executed upon contract creation, and where you can run contract +initialisation code. + +Before the constructor code is executed, state variables are initialised to +their specified value if you initialise them inline, or zero if you do not. + +After the constructor has run, the final code of the contract is deployed +to the blockchain. The deployment of +the code costs additional gas linear to the length of the code. +This code includes all functions that are part of the public interface +and all functions that are reachable from there through function calls. +It does not include the constructor code or internal functions that are +only called from the constructor. + +Constructor functions can be either ``public`` or ``internal``. If there is no +constructor, the contract will assume the default constructor, which is +equivalent to ``constructor() public {}``. For example: + +:: + + pragma solidity ^0.5.0; + + contract A { + uint public a; + + constructor(uint _a) internal { + a = _a; + } + } + + contract B is A(1) { + constructor() public {} + } + +A constructor set as ``internal`` causes the contract to be marked as :ref:`abstract <abstract-contract>`. + +.. warning :: + Prior to version 0.4.22, constructors were defined as functions with the same name as the contract. + This syntax was deprecated and is not allowed anymore in version 0.5.0. + + +.. index:: ! base;constructor + +Arguments for Base Constructors +=============================== + +The constructors of all the base contracts will be called following the +linearization rules explained below. If the base constructors have arguments, +derived contracts need to specify all of them. This can be done in two ways:: + + pragma solidity >=0.4.22 <0.6.0; + + contract Base { + uint x; + constructor(uint _x) public { x = _x; } + } + + // Either directly specify in the inheritance list... + contract Derived1 is Base(7) { + constructor() public {} + } + + // or through a "modifier" of the derived constructor. + contract Derived2 is Base { + constructor(uint _y) Base(_y * _y) public {} + } + +One way is directly in the inheritance list (``is Base(7)``). The other is in +the way a modifier is invoked as part of +the derived constructor (``Base(_y * _y)``). The first way to +do it is more convenient if the constructor argument is a +constant and defines the behaviour of the contract or +describes it. The second way has to be used if the +constructor arguments of the base depend on those of the +derived contract. Arguments have to be given either in the +inheritance list or in modifier-style in the derived constructor. +Specifying arguments in both places is an error. + +If a derived contract does not specify the arguments to all of its base +contracts' constructors, it will be abstract. + +.. index:: ! inheritance;multiple, ! linearization, ! C3 linearization + +.. _multi-inheritance: + +Multiple Inheritance and Linearization +====================================== + +Languages that allow multiple inheritance have to deal with +several problems. One is the `Diamond Problem <https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem>`_. +Solidity is similar to Python in that it uses "`C3 Linearization <https://en.wikipedia.org/wiki/C3_linearization>`_" +to force a specific order in the directed acyclic graph (DAG) of base classes. This +results in the desirable property of monotonicity but +disallows some inheritance graphs. Especially, the order in +which the base classes are given in the ``is`` directive is +important: You have to list the direct base contracts +in the order from "most base-like" to "most derived". +Note that this order is the reverse of the one used in Python. + +Another simplifying way to explain this is that when a function is called that +is defined multiple times in different contracts, the given bases +are searched from right to left (left to right in Python) in a depth-first manner, +stopping at the first match. If a base contract has already been searched, it is skipped. + +In the following code, Solidity will give the +error "Linearization of inheritance graph impossible". + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract X {} + contract A is X {} + // This will not compile + contract C is A, X {} + +The reason for this is that ``C`` requests ``X`` to override ``A`` +(by specifying ``A, X`` in this order), but ``A`` itself +requests to override ``X``, which is a contradiction that +cannot be resolved. + + + +Inheriting Different Kinds of Members of the Same Name +====================================================== + +When the inheritance results in a contract with a function and a modifier of the same name, it is considered as an error. +This error is produced also by an event and a modifier of the same name, and a function and an event of the same name. +As an exception, a state variable getter can override a public function. diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst new file mode 100644 index 00000000..b551b518 --- /dev/null +++ b/docs/contracts/interfaces.rst @@ -0,0 +1,36 @@ +.. index:: ! contract;interface, ! interface contract + +.. _interfaces: + +********** +Interfaces +********** + +Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions: + +- They cannot inherit other contracts or interfaces. +- All declared functions must be external. +- They cannot declare a constructor. +- They cannot declare state variables. + +Some of these restrictions might be lifted in the future. + +Interfaces are basically limited to what the Contract ABI can represent, and the conversion between the ABI and +an interface should be possible without any information loss. + +Interfaces are denoted by their own keyword: + +:: + + pragma solidity ^0.5.0; + + interface Token { + enum TokenType { Fungible, NonFungible } + struct Coin { string obverse; string reverse; } + function transfer(address recipient, uint amount) external; + } + +Contracts can inherit interfaces as they would inherit other contracts. + +Types defined inside interfaces and other contract-like structures +can be accessed from other contracts: ``Token.TokenType`` or ``Token.Coin``. diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst new file mode 100644 index 00000000..0cabe18a --- /dev/null +++ b/docs/contracts/libraries.rst @@ -0,0 +1,230 @@ +.. index:: ! library, callcode, delegatecall + +.. _libraries: + +********* +Libraries +********* + +Libraries are similar to contracts, but their purpose is that they are deployed +only once at a specific address and their code is reused using the ``DELEGATECALL`` +(``CALLCODE`` until Homestead) +feature of the EVM. This means that if library functions are called, their code +is executed in the context of the calling contract, i.e. ``this`` points to the +calling contract, and especially the storage from the calling contract can be +accessed. As a library is an isolated piece of source code, it can only access +state variables of the calling contract if they are explicitly supplied (it +would have no way to name them, otherwise). Library functions can only be +called directly (i.e. without the use of ``DELEGATECALL``) if they do not modify +the state (i.e. if they are ``view`` or ``pure`` functions), +because libraries are assumed to be stateless. In particular, it is +not possible to destroy a library. + +.. note:: + Until version 0.4.20, it was possible to destroy libraries by + circumventing Solidity's type system. Starting from that version, + libraries contain a :ref:`mechanism<call-protection>` that + disallows state-modifying functions + to be called directly (i.e. without ``DELEGATECALL``). + +Libraries can be seen as implicit base contracts of the contracts that use them. +They will not be explicitly visible in the inheritance hierarchy, but calls +to library functions look just like calls to functions of explicit base +contracts (``L.f()`` if ``L`` is the name of the library). Furthermore, +``internal`` functions of libraries are visible in all contracts, just as +if the library were a base contract. Of course, calls to internal functions +use the internal calling convention, which means that all internal types +can be passed and types :ref:`stored in memory <data-location>` will be passed by reference and not copied. +To realize this in the EVM, code of internal library functions +and all functions called from therein will at compile time be pulled into the calling +contract, and a regular ``JUMP`` call will be used instead of a ``DELEGATECALL``. + +.. index:: using for, set + +The following example illustrates how to use libraries (but manual method +be sure to check out :ref:`using for <using-for>` for a +more advanced example to implement a set). + +:: + + pragma solidity >=0.4.22 <0.6.0; + + library Set { + // We define a new struct datatype that will be used to + // hold its data in the calling contract. + struct Data { mapping(uint => bool) flags; } + + // Note that the first parameter is of type "storage + // reference" and thus only its storage address and not + // its contents is passed as part of the call. This is a + // special feature of library functions. It is idiomatic + // to call the first parameter `self`, if the function can + // be seen as a method of that object. + function insert(Data storage self, uint value) + public + returns (bool) + { + if (self.flags[value]) + return false; // already there + self.flags[value] = true; + return true; + } + + function remove(Data storage self, uint value) + public + returns (bool) + { + if (!self.flags[value]) + return false; // not there + self.flags[value] = false; + return true; + } + + function contains(Data storage self, uint value) + public + view + returns (bool) + { + return self.flags[value]; + } + } + + contract C { + Set.Data knownValues; + + function register(uint value) public { + // The library functions can be called without a + // specific instance of the library, since the + // "instance" will be the current contract. + require(Set.insert(knownValues, value)); + } + // In this contract, we can also directly access knownValues.flags, if we want. + } + +Of course, you do not have to follow this way to use +libraries: they can also be used without defining struct +data types. Functions also work without any storage +reference parameters, and they can have multiple storage reference +parameters and in any position. + +The calls to ``Set.contains``, ``Set.insert`` and ``Set.remove`` +are all compiled as calls (``DELEGATECALL``) to an external +contract/library. If you use libraries, be aware that an +actual external function call is performed. +``msg.sender``, ``msg.value`` and ``this`` will retain their values +in this call, though (prior to Homestead, because of the use of ``CALLCODE``, ``msg.sender`` and +``msg.value`` changed, though). + +The following example shows how to use :ref:`types stored in memory <data-location>` and +internal functions in libraries in order to implement +custom types without the overhead of external function calls: + +:: + + pragma solidity >=0.4.16 <0.6.0; + + library BigInt { + struct bigint { + uint[] limbs; + } + + function fromUint(uint x) internal pure returns (bigint memory r) { + r.limbs = new uint[](1); + r.limbs[0] = x; + } + + function add(bigint memory _a, bigint memory _b) internal pure returns (bigint memory r) { + r.limbs = new uint[](max(_a.limbs.length, _b.limbs.length)); + uint carry = 0; + for (uint i = 0; i < r.limbs.length; ++i) { + uint a = limb(_a, i); + uint b = limb(_b, i); + r.limbs[i] = a + b + carry; + if (a + b < a || (a + b == uint(-1) && carry > 0)) + carry = 1; + else + carry = 0; + } + if (carry > 0) { + // too bad, we have to add a limb + uint[] memory newLimbs = new uint[](r.limbs.length + 1); + uint i; + for (i = 0; i < r.limbs.length; ++i) + newLimbs[i] = r.limbs[i]; + newLimbs[i] = carry; + r.limbs = newLimbs; + } + } + + function limb(bigint memory _a, uint _limb) internal pure returns (uint) { + return _limb < _a.limbs.length ? _a.limbs[_limb] : 0; + } + + function max(uint a, uint b) private pure returns (uint) { + return a > b ? a : b; + } + } + + contract C { + using BigInt for BigInt.bigint; + + function f() public pure { + BigInt.bigint memory x = BigInt.fromUint(7); + BigInt.bigint memory y = BigInt.fromUint(uint(-1)); + BigInt.bigint memory z = x.add(y); + assert(z.limb(1) > 0); + } + } + +As the compiler cannot know where the library will be +deployed at, these addresses have to be filled into the +final bytecode by a linker +(see :ref:`commandline-compiler` for how to use the +commandline compiler for linking). If the addresses are not +given as arguments to the compiler, the compiled hex code +will contain placeholders of the form ``__Set______`` (where +``Set`` is the name of the library). The address can be filled +manually by replacing all those 40 symbols by the hex +encoding of the address of the library contract. + +.. note:: + Manually linking libraries on the generated bytecode is discouraged, because + it is restricted to 36 characters. + You should ask the compiler to link the libraries at the time + a contract is compiled by either using + the ``--libraries`` option of ``solc`` or the ``libraries`` key if you use + the standard-JSON interface to the compiler. + +Restrictions for libraries in comparison to contracts: + +- No state variables +- Cannot inherit nor be inherited +- Cannot receive Ether + +(These might be lifted at a later point.) + +.. _call-protection: + +Call Protection For Libraries +============================= + +As mentioned in the introduction, if a library's code is executed +using a ``CALL`` instead of a ``DELEGATECALL`` or ``CALLCODE``, +it will revert unless a ``view`` or ``pure`` function is called. + +The EVM does not provide a direct way for a contract to detect +whether it was called using ``CALL`` or not, but a contract +can use the ``ADDRESS`` opcode to find out "where" it is +currently running. The generated code compares this address +to the address used at construction time to determine the mode +of calling. + +More specifically, the runtime code of a library always starts +with a push instruction, which is a zero of 20 bytes at +compilation time. When the deploy code runs, this constant +is replaced in memory by the current address and this +modified code is stored in the contract. At runtime, +this causes the deploy time address to be the first +constant to be pushed onto the stack and the dispatcher +code compares the current address against this constant +for any non-view and non-pure function. diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst new file mode 100644 index 00000000..ef456ff4 --- /dev/null +++ b/docs/contracts/using-for.rst @@ -0,0 +1,119 @@ +.. index:: ! using for, library + +.. _using-for: + +********* +Using For +********* + +The directive ``using A for B;`` can be used to attach library +functions (from the library ``A``) to any type (``B``). +These functions will receive the object they are called on +as their first parameter (like the ``self`` variable in Python). + +The effect of ``using A for *;`` is that the functions from +the library ``A`` are attached to *any* type. + +In both situations, *all* functions in the library are attached, +even those where the type of the first parameter does not +match the type of the object. The type is checked at the +point the function is called and function overload +resolution is performed. + +The ``using A for B;`` directive is active only within the current +contract, including within all of its functions, and has no effect +outside of the contract in which it is used. The directive +may only be used inside a contract, not inside any of its functions. + +By including a library, its data types including library functions are +available without having to add further code. + +Let us rewrite the set example from the +:ref:`libraries` in this way:: + + pragma solidity >=0.4.16 <0.6.0; + + // This is the same code as before, just without comments + library Set { + struct Data { mapping(uint => bool) flags; } + + function insert(Data storage self, uint value) + public + returns (bool) + { + if (self.flags[value]) + return false; // already there + self.flags[value] = true; + return true; + } + + function remove(Data storage self, uint value) + public + returns (bool) + { + if (!self.flags[value]) + return false; // not there + self.flags[value] = false; + return true; + } + + function contains(Data storage self, uint value) + public + view + returns (bool) + { + return self.flags[value]; + } + } + + contract C { + using Set for Set.Data; // this is the crucial change + Set.Data knownValues; + + function register(uint value) public { + // Here, all variables of type Set.Data have + // corresponding member functions. + // The following function call is identical to + // `Set.insert(knownValues, value)` + require(knownValues.insert(value)); + } + } + +It is also possible to extend elementary types in that way:: + + pragma solidity >=0.4.16 <0.6.0; + + library Search { + function indexOf(uint[] storage self, uint value) + public + view + returns (uint) + { + for (uint i = 0; i < self.length; i++) + if (self[i] == value) return i; + return uint(-1); + } + } + + contract C { + using Search for uint[]; + uint[] data; + + function append(uint value) public { + data.push(value); + } + + function replace(uint _old, uint _new) public { + // This performs the library function call + uint index = data.indexOf(_old); + if (index == uint(-1)) + data.push(_new); + else + data[index] = _new; + } + } + +Note that all library calls are actual EVM function calls. This means that +if you pass memory or value types, a copy will be performed, even of the +``self`` variable. The only situation where no copy will be performed +is when storage reference variables are used. diff --git a/docs/contracts/visibility-and-getters.rst b/docs/contracts/visibility-and-getters.rst new file mode 100644 index 00000000..e78c9674 --- /dev/null +++ b/docs/contracts/visibility-and-getters.rst @@ -0,0 +1,198 @@ +.. index:: ! visibility, external, public, private, internal + +.. _visibility-and-getters: + +********************** +Visibility and Getters +********************** + +Since Solidity knows two kinds of function calls (internal +ones that do not create an actual EVM call (also called +a "message call") and external +ones that do), there are four types of visibilities for +functions and state variables. + +Functions have to be specified as being ``external``, +``public``, ``internal`` or ``private``. +For state variables, ``external`` is not possible. + +``external``: + External functions are part of the contract interface, + which means they can be called from other contracts and + via transactions. An external function ``f`` cannot be called + internally (i.e. ``f()`` does not work, but ``this.f()`` works). + External functions are sometimes more efficient when + they receive large arrays of data. + +``public``: + Public functions are part of the contract interface + and can be either called internally or via + messages. For public state variables, an automatic getter + function (see below) is generated. + +``internal``: + Those functions and state variables can only be + accessed internally (i.e. from within the current contract + or contracts deriving from it), without using ``this``. + +``private``: + Private functions and state variables are only + visible for the contract they are defined in and not in + derived contracts. + +.. note:: + Everything that is inside a contract is visible to + all observers external to the blockchain. Making something ``private`` + only prevents other contracts from accessing and modifying + the information, but it will still be visible to the + whole world outside of the blockchain. + +The visibility specifier is given after the type for +state variables and between parameter list and +return parameter list for functions. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + contract C { + function f(uint a) private pure returns (uint b) { return a + 1; } + function setData(uint a) internal { data = a; } + uint public data; + } + +In the following example, ``D``, can call ``c.getData()`` to retrieve the value of +``data`` in state storage, but is not able to call ``f``. Contract ``E`` is derived from +``C`` and, thus, can call ``compute``. + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract C { + uint private data; + + function f(uint a) private pure returns(uint b) { return a + 1; } + function setData(uint a) public { data = a; } + function getData() public view returns(uint) { return data; } + function compute(uint a, uint b) internal pure returns (uint) { return a + b; } + } + + // This will not compile + contract D { + function readData() public { + C c = new C(); + uint local = c.f(7); // error: member `f` is not visible + c.setData(3); + local = c.getData(); + local = c.compute(3, 5); // error: member `compute` is not visible + } + } + + contract E is C { + function g() public { + C c = new C(); + uint val = compute(3, 5); // access to internal member (from derived to parent contract) + } + } + +.. index:: ! getter;function, ! function;getter +.. _getter-functions: + +Getter Functions +================ + +The compiler automatically creates getter functions for +all **public** state variables. For the contract given below, the compiler will +generate a function called ``data`` that does not take any +arguments and returns a ``uint``, the value of the state +variable ``data``. State variables can be initialized +when they are declared. + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract C { + uint public data = 42; + } + + contract Caller { + C c = new C(); + function f() public view returns (uint) { + return c.data(); + } + } + +The getter functions have external visibility. If the +symbol is accessed internally (i.e. without ``this.``), +it evaluates to a state variable. If it is accessed externally +(i.e. with ``this.``), it evaluates to a function. + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract C { + uint public data; + function x() public returns (uint) { + data = 3; // internal access + return this.data(); // external access + } + } + +If you have a ``public`` state variable of array type, then you can only retrieve +single elements of the array via the generated getter function. This mechanism +exists to avoid high gas costs when returning an entire array. You can use +arguments to specify which individual element to return, for example +``data(0)``. If you want to return an entire array in one call, then you need +to write a function, for example: + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract arrayExample { + // public state variable + uint[] public myArray; + + // Getter function generated by the compiler + /* + function myArray(uint i) returns (uint) { + return myArray[i]; + } + */ + + // function that returns entire array + function getArray() returns (uint[] memory) { + return myArray; + } + } + +Now you can use ``getArray()`` to retrieve the entire array, instead of +``myArray(i)``, which returns a single element per call. + +The next example is more complex: + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract Complex { + struct Data { + uint a; + bytes3 b; + mapping (uint => uint) map; + } + mapping (uint => mapping(bool => Data[])) public data; + } + +It generates a function of the following form. The mapping in the struct is omitted +because there is no good way to provide the key for the mapping: + +:: + + function data(uint arg1, bool arg2, uint arg3) public returns (uint a, bytes3 b) { + a = data[arg1][arg2][arg3].a; + b = data[arg1][arg2][arg3].b; + } |