diff options
| -rw-r--r-- | docs/conf.py | 2 | ||||
| -rw-r--r-- | docs/contracts.rst | 1325 | ||||
| -rw-r--r-- | docs/contracts/abstract-contracts.rst | 43 | ||||
| -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/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 | ||||
| -rw-r--r-- | test/libyul/yulOptimizerTests/fullSuite/aztec.yul | 416 |
12 files changed, 1740 insertions, 1317 deletions
diff --git a/docs/conf.py b/docs/conf.py index 08a5a045..342aefa9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -81,7 +81,7 @@ else: # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ['_build', 'contracts'] # The reST default role (used for this markup: `text`) to use for all # documents. diff --git a/docs/contracts.rst b/docs/contracts.rst index 6d31ad82..859cd9e9 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -12,434 +12,11 @@ variables. Calling a function on a different contract (instance) will perform an EVM function call and thus switch the context such that state variables are inaccessible. -.. index:: ! contract;creation, constructor +.. include:: contracts/creating-contracts.rst -****************** -Creating Contracts -****************** +.. include:: contracts/visibility-and-getters.rst -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 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; - } - } - -.. 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; - } - -.. 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). +.. include:: contracts/function-modifiers.rst .. include:: contracts/constant-state-variables.rst @@ -842,897 +419,13 @@ Calling ``f(50)`` would create a type error since ``50`` can be implicitly conve and ``uint256`` types. On another hand ``f(256)`` would resolve to ``f(uint256)`` overload as ``256`` cannot be implicitly converted to ``uint8``. -.. 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>`_ - -.. 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; - } +.. include:: contracts/events.rst - function get() public view returns(uint r) { return info; } +.. include:: contracts/inheritance.rst - 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. - -.. 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". - - -.. index:: ! contract;interface, ! interface contract - -.. _interfaces: - -********** -Interfaces -********** - -Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions: +.. include:: contracts/abstract-contracts.rst +.. include:: contracts/interfaces.rst -- 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``. - -.. 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. - -.. 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; - } - } +.. include:: contracts/libraries.rst -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. +.. include:: contracts/using-for.rst
\ No newline at end of file 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/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/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; + } diff --git a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul new file mode 100644 index 00000000..e43a066c --- /dev/null +++ b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul @@ -0,0 +1,416 @@ +/** + * @title Library to validate AZTEC zero-knowledge proofs + * @author Zachary Williamson, AZTEC + * @dev Don't include this as an internal library. This contract uses a static memory table to cache elliptic curve primitives and hashes. + * Calling this internally from another function will lead to memory mutation and undefined behaviour. + * The intended use case is to call this externally via `staticcall`. External calls to OptimizedAZTEC can be treated as pure functions as this contract contains no storage and makes no external calls (other than to precompiles) + * Copyright Spilbury Holdings Ltd 2018. All rights reserved. + * We will be releasing AZTEC as an open-source protocol that provides efficient transaction privacy for Ethereum. + * This will include our bespoke AZTEC decentralized exchange, allowing for cross-asset transfers with full transaction privacy + * and interopability with public decentralized exchanges. + * Stay tuned for updates! + * + * Permission to use as test case in the Solidity compiler granted by the author: + * https://github.com/ethereum/solidity/pull/5713#issuecomment-449042830 +**/ +{ + validateJoinSplit() + // should not get here + mstore(0x00, 404) + revert(0x00, 0x20) + + + function validateJoinSplit() { + mstore(0x80, 7673901602397024137095011250362199966051872585513276903826533215767972925880) // h_x + mstore(0xa0, 8489654445897228341090914135473290831551238522473825886865492707826370766375) // h_y + let notes := add(0x04, calldataload(0x04)) + let m := calldataload(0x24) + let n := calldataload(notes) + let gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + let challenge := mod(calldataload(0x44), gen_order) + + // validate m <= n + if gt(m, n) { mstore(0x00, 404) revert(0x00, 0x20) } + + // recover k_{public} and calculate k_{public} + let kn := calldataload(sub(calldatasize(), 0xc0)) + + // add kn and m to final hash table + mstore(0x2a0, caller()) + mstore(0x2c0, kn) + mstore(0x2e0, m) + kn := mulmod(sub(gen_order, kn), challenge, gen_order) // we actually want c*k_{public} + hashCommitments(notes, n) + let b := add(0x300, mul(n, 0x80)) + + // Iterate over every note and calculate the blinding factor B_i = \gamma_i^{kBar}h^{aBar}\sigma_i^{-c}. + // We use the AZTEC protocol pairing optimization to reduce the number of pairing comparisons to 1, which adds some minor alterations + for { let i := 0 } lt(i, n) { i := add(i, 0x01) } { + + // Get the calldata index of this note + let noteIndex := add(add(notes, 0x20), mul(i, 0xc0)) + + + let k + let a := calldataload(add(noteIndex, 0x20)) + let c := challenge + + switch eq(add(i, 0x01), n) + case 1 { + k := kn + + // if all notes are input notes, invert k + if eq(m, n) { + k := sub(gen_order, k) + } + } + case 0 { k := calldataload(noteIndex) } + + // Check this commitment is well formed... + validateCommitment(noteIndex, k, a) + + // If i > m then this is an output note. + // Set k = kx_j, a = ax_j, c = cx_j, where j = i - (m+1) + switch gt(add(i, 0x01), m) + case 1 { + + // before we update k, update kn = \sum_{i=0}^{m-1}k_i - \sum_{i=m}^{n-1}k_i + kn := addmod(kn, sub(gen_order, k), gen_order) + let x := mod(mload(0x00), gen_order) + k := mulmod(k, x, gen_order) + a := mulmod(a, x, gen_order) + c := mulmod(challenge, x, gen_order) + + // calculate x_{j+1} + mstore(0x00, keccak256(0x00, 0x20)) + } + case 0 { + + // nothing to do here except update kn = \sum_{i=0}^{m-1}k_i - \sum_{i=m}^{n-1}k_i + kn := addmod(kn, k, gen_order) + } + + calldatacopy(0xe0, add(noteIndex, 0x80), 0x40) + calldatacopy(0x20, add(noteIndex, 0x40), 0x40) + mstore(0x120, sub(gen_order, c)) + mstore(0x60, k) + mstore(0xc0, a) + + // Using call instead of staticcall here to make it work on all targets. + let result := call(gas(), 7, 0, 0xe0, 0x60, 0x1a0, 0x40) + result := and(result, call(gas(), 7, 0, 0x20, 0x60, 0x120, 0x40)) + result := and(result, call(gas(), 7, 0, 0x80, 0x60, 0x160, 0x40)) + + result := and(result, call(gas(), 6, 0, 0x120, 0x80, 0x160, 0x40)) + + result := and(result, call(gas(), 6, 0, 0x160, 0x80, b, 0x40)) + + if eq(i, m) { + mstore(0x260, mload(0x20)) + mstore(0x280, mload(0x40)) + mstore(0x1e0, mload(0xe0)) + mstore(0x200, sub(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47, mload(0x100))) + } + + if gt(i, m) { + mstore(0x60, c) + result := and(result, call(gas(), 7, 0, 0x20, 0x60, 0x220, 0x40)) + + result := and(result, call(gas(), 6, 0, 0x220, 0x80, 0x260, 0x40)) + result := and(result, call(gas(), 6, 0, 0x1a0, 0x80, 0x1e0, 0x40)) + } + + if iszero(result) { mstore(0x00, 400) revert(0x00, 0x20) } + b := add(b, 0x40) // increase B pointer by 2 words + } + + if lt(m, n) { + validatePairing(0x64) + } + + let expected := mod(keccak256(0x2a0, sub(b, 0x2a0)), gen_order) + if iszero(eq(expected, challenge)) { + + // No! Bad! No soup for you! + mstore(0x00, 404) + revert(0x00, 0x20) + } + + // Great! All done. This is a valid proof so return ```true``` + mstore(0x00, 0x01) + return(0x00, 0x20) + } + + function validatePairing(t2) { + let field_order := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + let t2_x_1 := calldataload(t2) + let t2_x_2 := calldataload(add(t2, 0x20)) + let t2_y_1 := calldataload(add(t2, 0x40)) + let t2_y_2 := calldataload(add(t2, 0x60)) + + // check provided setup pubkey is not zero or g2 + if or(or(or(or(or(or(or( + iszero(t2_x_1), + iszero(t2_x_2)), + iszero(t2_y_1)), + iszero(t2_y_2)), + eq(t2_x_1, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed)), + eq(t2_x_2, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2)), + eq(t2_y_1, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa)), + eq(t2_y_2, 0x90689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b)) + { + mstore(0x00, 400) + revert(0x00, 0x20) + } + + mstore(0x20, mload(0x1e0)) // sigma accumulator x + mstore(0x40, mload(0x200)) // sigma accumulator y + mstore(0x80, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x60, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0xc0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) + mstore(0xa0, 0x90689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0xe0, mload(0x260)) // gamma accumulator x + mstore(0x100, mload(0x280)) // gamma accumulator y + mstore(0x140, t2_x_1) + mstore(0x120, t2_x_2) + mstore(0x180, t2_y_1) + mstore(0x160, t2_y_2) + + let success := call(gas(), 8, 0, 0x20, 0x180, 0x20, 0x20) + + if or(iszero(success), iszero(mload(0x20))) { + mstore(0x00, 400) + revert(0x00, 0x20) + } + } + + function validateCommitment(note, k, a) { + let gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + let field_order := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + let gammaX := calldataload(add(note, 0x40)) + let gammaY := calldataload(add(note, 0x60)) + let sigmaX := calldataload(add(note, 0x80)) + let sigmaY := calldataload(add(note, 0xa0)) + if iszero( + and( + and( + and( + eq(mod(a, gen_order), a), // a is modulo generator order? + gt(a, 1) // can't be 0 or 1 either! + ), + and( + eq(mod(k, gen_order), k), // k is modulo generator order? + gt(k, 1) // and not 0 or 1 + ) + ), + and( + eq( // y^2 ?= x^3 + 3 + addmod(mulmod(mulmod(sigmaX, sigmaX, field_order), sigmaX, field_order), 3, field_order), + mulmod(sigmaY, sigmaY, field_order) + ), + eq( // y^2 ?= x^3 + 3 + addmod(mulmod(mulmod(gammaX, gammaX, field_order), gammaX, field_order), 3, field_order), + mulmod(gammaY, gammaY, field_order) + ) + ) + ) + ) { + mstore(0x00, 400) + revert(0x00, 0x20) + } + } + + function hashCommitments(notes, n) { + for { let i := 0 } lt(i, n) { i := add(i, 0x01) } { + let index := add(add(notes, mul(i, 0xc0)), 0x60) + calldatacopy(add(0x300, mul(i, 0x80)), index, 0x80) + } + mstore(0x00, keccak256(0x300, mul(n, 0x80))) + } +} +// ---- +// fullSuite +// { +// { +// let validateJo__6 := 0x80 +// mstore(validateJo__6, 7673901602397024137095011250362199966051872585513276903826533215767972925880) +// mstore(0xa0, 8489654445897228341090914135473290831551238522473825886865492707826370766375) +// let validateJo__10 := calldataload(0x04) +// let validateJo_notes := add(0x04, validateJo__10) +// let validateJo_m := calldataload(0x24) +// let validateJo_n := calldataload(validateJo_notes) +// let validateJo_gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// let validateJo_challenge := mod(calldataload(0x44), validateJo_gen_order) +// if gt(validateJo_m, validateJo_n) +// { +// mstore(0x00, 404) +// revert(0x00, 0x20) +// } +// let validateJo_kn_287 := calldataload(add(calldatasize(), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40)) +// let validateJo_kn := validateJo_kn_287 +// let validateJo__24 := 0x2a0 +// mstore(validateJo__24, caller()) +// mstore(0x2c0, validateJo_kn_287) +// mstore(0x2e0, validateJo_m) +// validateJo_kn := mulmod(sub(validateJo_gen_order, validateJo_kn_287), validateJo_challenge, validateJo_gen_order) +// hashCommitments(validateJo_notes, validateJo_n) +// let validateJo_b := add(0x300, mul(validateJo_n, validateJo__6)) +// let validateJo_i_290 := 0 +// let validateJo_i := validateJo_i_290 +// for { +// } +// lt(validateJo_i, validateJo_n) +// { +// validateJo_i := add(validateJo_i, 0x01) +// } +// { +// let validateJo__34 := 0x20 +// let validateJo__376 := add(validateJo__10, mul(validateJo_i, 0xc0)) +// let validateJo_noteIndex := add(validateJo__376, 36) +// let validateJo_k := validateJo_i_290 +// let validateJo_a_292 := calldataload(add(validateJo__376, 68)) +// let validateJo_a := validateJo_a_292 +// let validateJo_c := validateJo_challenge +// let validateJo__39 := add(validateJo_i, 0x01) +// switch eq(validateJo__39, validateJo_n) +// case 1 { +// validateJo_k := validateJo_kn +// if eq(validateJo_m, validateJo_n) +// { +// validateJo_k := sub(validateJo_gen_order, validateJo_kn) +// } +// } +// case 0 { +// validateJo_k := calldataload(validateJo_noteIndex) +// } +// validateCommitment(validateJo_noteIndex, validateJo_k, validateJo_a_292) +// switch gt(validateJo__39, validateJo_m) +// case 1 { +// validateJo_kn := addmod(validateJo_kn, sub(validateJo_gen_order, validateJo_k), validateJo_gen_order) +// let validateJo_x := mod(mload(0x00), validateJo_gen_order) +// validateJo_k := mulmod(validateJo_k, validateJo_x, validateJo_gen_order) +// validateJo_a := mulmod(validateJo_a_292, validateJo_x, validateJo_gen_order) +// validateJo_c := mulmod(validateJo_challenge, validateJo_x, validateJo_gen_order) +// mstore(0x00, keccak256(0x00, validateJo__34)) +// } +// case 0 { +// validateJo_kn := addmod(validateJo_kn, validateJo_k, validateJo_gen_order) +// } +// let validateJo__52 := 0x40 +// calldatacopy(0xe0, add(validateJo__376, 164), validateJo__52) +// calldatacopy(validateJo__34, add(validateJo__376, 100), validateJo__52) +// let validateJo__61 := 0x120 +// mstore(validateJo__61, sub(validateJo_gen_order, validateJo_c)) +// let validateJo__62 := 0x60 +// mstore(validateJo__62, validateJo_k) +// mstore(0xc0, validateJo_a) +// let validateJo__65 := 0x1a0 +// let validateJo_result_302 := call(gas(), 7, validateJo_i_290, 0xe0, validateJo__62, validateJo__65, validateJo__52) +// let validateJo_result := validateJo_result_302 +// let validateJo_result_303 := and(validateJo_result_302, call(gas(), 7, validateJo_i_290, validateJo__34, validateJo__62, validateJo__61, validateJo__52)) +// let validateJo__80 := 0x160 +// let validateJo_result_304 := and(validateJo_result_303, call(gas(), 7, validateJo_i_290, validateJo__6, validateJo__62, validateJo__80, validateJo__52)) +// let validateJo_result_305 := and(validateJo_result_304, call(gas(), 6, validateJo_i_290, validateJo__61, validateJo__6, validateJo__80, validateJo__52)) +// let validateJo_result_306 := and(validateJo_result_305, call(gas(), 6, validateJo_i_290, validateJo__80, validateJo__6, validateJo_b, validateJo__52)) +// validateJo_result := validateJo_result_306 +// if eq(validateJo_i, validateJo_m) +// { +// mstore(0x260, mload(validateJo__34)) +// mstore(0x280, mload(validateJo__52)) +// mstore(0x1e0, mload(0xe0)) +// mstore(0x200, sub(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47, mload(0x100))) +// } +// if gt(validateJo_i, validateJo_m) +// { +// mstore(validateJo__62, validateJo_c) +// let validateJo__120 := 0x220 +// let validateJo_result_307 := and(validateJo_result_306, call(gas(), 7, validateJo_i_290, validateJo__34, validateJo__62, validateJo__120, validateJo__52)) +// let validateJo_result_308 := and(validateJo_result_307, call(gas(), 6, validateJo_i_290, validateJo__120, validateJo__6, 0x260, validateJo__52)) +// validateJo_result := and(validateJo_result_308, call(gas(), 6, validateJo_i_290, validateJo__65, validateJo__6, 0x1e0, validateJo__52)) +// } +// if iszero(validateJo_result) +// { +// mstore(0x00, 400) +// revert(0x00, validateJo__34) +// } +// validateJo_b := add(validateJo_b, validateJo__52) +// } +// if lt(validateJo_m, validateJo_n) +// { +// validatePairing(0x64) +// } +// if iszero(eq(mod(keccak256(validateJo__24, add(validateJo_b, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60)), validateJo_gen_order), validateJo_challenge)) +// { +// mstore(0x00, 404) +// revert(0x00, 0x20) +// } +// mstore(0x00, 0x01) +// return(0x00, 0x20) +// mstore(0x00, 404) +// revert(0x00, 0x20) +// } +// function validatePairing(t2) +// { +// let t2_x_1 := calldataload(t2) +// let _165 := 0x20 +// let t2_x_2 := calldataload(add(t2, _165)) +// let t2_y_1 := calldataload(add(t2, 0x40)) +// let t2_y_2 := calldataload(add(t2, 0x60)) +// let _171 := 0x90689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b +// let _173 := 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa +// let _175 := 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2 +// let _177 := 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed +// if or(or(or(or(or(or(or(iszero(t2_x_1), iszero(t2_x_2)), iszero(t2_y_1)), iszero(t2_y_2)), eq(t2_x_1, _177)), eq(t2_x_2, _175)), eq(t2_y_1, _173)), eq(t2_y_2, _171)) +// { +// mstore(0x00, 400) +// revert(0x00, _165) +// } +// mstore(_165, mload(0x1e0)) +// mstore(0x40, mload(0x200)) +// mstore(0x80, _177) +// mstore(0x60, _175) +// mstore(0xc0, _173) +// mstore(0xa0, _171) +// mstore(0xe0, mload(0x260)) +// mstore(0x100, mload(0x280)) +// mstore(0x140, t2_x_1) +// mstore(0x120, t2_x_2) +// let _216 := 0x180 +// mstore(_216, t2_y_1) +// mstore(0x160, t2_y_2) +// let success := call(gas(), 8, 0, _165, _216, _165, _165) +// if or(iszero(success), iszero(mload(_165))) +// { +// mstore(0x00, 400) +// revert(0x00, _165) +// } +// } +// function validateCommitment(note, k_1, a_2) +// { +// let gen_order_3 := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// let field_order_4 := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 +// let gammaX := calldataload(add(note, 0x40)) +// let gammaY := calldataload(add(note, 0x60)) +// let sigmaX := calldataload(add(note, 0x80)) +// let sigmaY := calldataload(add(note, 0xa0)) +// if iszero(and(and(and(eq(mod(a_2, gen_order_3), a_2), gt(a_2, 1)), and(eq(mod(k_1, gen_order_3), k_1), gt(k_1, 1))), and(eq(addmod(mulmod(mulmod(sigmaX, sigmaX, field_order_4), sigmaX, field_order_4), 3, field_order_4), mulmod(sigmaY, sigmaY, field_order_4)), eq(addmod(mulmod(mulmod(gammaX, gammaX, field_order_4), gammaX, field_order_4), 3, field_order_4), mulmod(gammaY, gammaY, field_order_4))))) +// { +// mstore(0x00, 400) +// revert(0x00, 0x20) +// } +// } +// function hashCommitments(notes_5, n_6) +// { +// let i_7 := 0 +// for { +// } +// lt(i_7, n_6) +// { +// i_7 := add(i_7, 0x01) +// } +// { +// calldatacopy(add(0x300, mul(i_7, 0x80)), add(add(notes_5, mul(i_7, 0xc0)), 0x60), 0x80) +// } +// mstore(0x00, keccak256(0x300, mul(n_6, 0x80))) +// } +// } |
