functions.rst 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. Functions
  2. =========
  3. A function can be declared inside a contract, in which case it has access to the contracts
  4. contract storage variables, other contract functions etc. Functions can be also be declared outside
  5. a contract.
  6. .. include:: ../examples/functions.sol
  7. :code: solidity
  8. Function can have any number of arguments. Function arguments may have names;
  9. if they do not have names then they cannot be used in the function body, but they will
  10. be present in the public interface.
  11. The return values may have names as demonstrated in the get_initial_bound() function.
  12. When at all of the return values have a name, then the return statement is no
  13. longer required at the end of a function body. In stead of returning the values
  14. which are provided in the return statement, the values of the return variables at the end
  15. of the function is returned. It is still possible to explicitly return some values
  16. with a return statement.
  17. Any DocComment before a function will be include in the ABI. Currently only Substrate
  18. supports documentation in the ABI.
  19. Function visibility
  20. ___________________
  21. Solidity functions have a visibility specifier that restricts the scope in which they can be called.
  22. Functions can be declared public, private, internal or external with the following definitions:
  23. - ``public`` functions can be called inside and outside a contract (e.g. by an RPC). They are
  24. present in the contract's ABI or IDL.
  25. - ``private`` functions can only be called inside the contract they are declared.
  26. - ``internal`` functions can only be called internally within the contract or by any contract
  27. inherited contract.
  28. - ``external`` functions can exclusively be called by other contracts or directly by an RPC. They
  29. are also present in the contract's ABI or IDL.
  30. Both public and external functions can be called using the syntax ``this.func()``. In this case, the
  31. arguments are ABI encoded for the call, as it is treated like an external call. This is the only way to
  32. call an external function from inside the same contract it is defined. This method, however, should be avoided
  33. for public functions, as it will be more costly to call them than simply using ``func()``.
  34. If a function is defined outside a contract, it cannot have a visibility specifier (e.g. ``public``).
  35. Arguments passing and return values
  36. ___________________________________
  37. Function arguments can be passed either by position or by name. When they are called
  38. by name, arguments can be in any order. However, functions with anonymous arguments
  39. (arguments without name) cannot be called this way.
  40. .. include:: ../examples/function_arguments.sol
  41. :code: solidity
  42. If the function has a single return value, this can be assigned to a variable. If
  43. the function has multiple return values, these can be assigned using the :ref:`destructuring`
  44. assignment statement:
  45. .. include:: ../examples/function_destructing_arguments.sol
  46. :code: solidity
  47. It is also possible to call functions on other contracts, which is also known as calling
  48. external functions. The called function must be declared public.
  49. Calling external functions requires ABI encoding the arguments, and ABI decoding the
  50. return values. This much more costly than an internal function call.
  51. .. include:: ../examples/function_call_external.sol
  52. :code: solidity
  53. The syntax for calling external call is the same as the external call, except for
  54. that it must be done on a contract type variable. Any error in an external call can
  55. be handled with :ref:`try-catch`.
  56. Internal calls and externals calls
  57. ___________________________________
  58. An internal function call is executed by the current contract. This
  59. is much more efficient than an external call, which requires the
  60. address of the contract to call, whose arguments must be *abi encoded* (also known
  61. as serialization). Then, the runtime must set up the VM for the called contract
  62. (the callee), decode the arguments, and encode return values. Lastly,
  63. the first contract (the caller) must decode return values.
  64. A method call done on a contract type will always be an external call.
  65. Note that ``this`` returns the current contract, so ``this.foo()`` will do an
  66. external call, which is much more expensive than ``foo()``.
  67. .. _solana_external_call:
  68. Passing accounts with external calls on Solana
  69. ______________________________________________
  70. The Solana runtime allows you the specify the accounts to be passed for an
  71. external call. This is specified in an array of the struct ``AccountMeta``,
  72. see the section on :ref:`account_meta`.
  73. .. include:: ../examples/solana/function_call_external_accounts.sol
  74. :code: solidity
  75. If ``{accounts}`` is not specified, all accounts passed to the current transaction are forwarded to the call.
  76. Passing seeds with external calls on Solana
  77. ___________________________________________
  78. The Solana runtime allows you to specify the seeds to be passed for an
  79. external call. This is used for program derived addresses: the seeds are
  80. hashed with the calling program id to create program derived addresses.
  81. They will automatically have the signer bit set, which allows a contract to
  82. sign without using any private keys.
  83. .. include:: ../examples/solana/function_call_external_seeds.sol
  84. :code: solidity
  85. Now if the program derived address for the running program id and the seeds match the address
  86. ``addr`` and ``addr2``, then then the called program will run with signer and writable bits
  87. set for ``addr`` and ``addr2``. If they do not match, the Solana runtime will detect that
  88. the ``is_signer`` is set without the correct signature being provided.
  89. The seeds can provided in any other, which will be used to sign for multiple accounts. In the example
  90. above, the seed ``"test"`` is concatenated with the value of ``seed``, and that produces
  91. one account signature. In adition, ``"foo"`` is concatenated with ``"bar"`` to produce ``"foobar"``
  92. and then used to sign for another account.
  93. The ``seeds:`` call parameter is a slice of bytes slices; this means the literal can contain any
  94. number of elements, including 0 elements. The values can be ``bytes`` or anything that can be
  95. cast to ``bytes``.
  96. .. _passing_value_gas:
  97. Passing value and gas with external calls
  98. _________________________________________
  99. For external calls, value can be sent along with the call. The callee must be
  100. ``payable``. Likewise, a gas limit can be set.
  101. .. include:: ../examples/substrate/function_call_external_gas.sol
  102. :code: solidity
  103. .. note::
  104. The gas cannot be set on Solana for external calls.
  105. State mutability
  106. ________________
  107. Some functions only read contract storage (also known as *state*), and others may write
  108. contract storage. Functions that do not write state can be executed off-chain. Off-chain
  109. execution is faster, does not require write access, and does not need any balance.
  110. Functions that do not write state come in two flavours: ``view`` and ``pure``. ``pure``
  111. functions may not read state, and ``view`` functions that do read state.
  112. Functions that do write state come in two flavours: ``payable`` and non-payable, the
  113. default. Functions that are not intended to receive any value, should not be marked
  114. ``payable``. The compiler will check that every call does not included any value, and
  115. there are runtime checks as well, which cause the function to be reverted if value is
  116. sent.
  117. A constructor can be marked ``payable``, in which case value can be passed with the
  118. constructor.
  119. .. note::
  120. If value is sent to a non-payable function on Parity Substrate, the call will be
  121. reverted. However there is no refund performed, so value will remain with the callee.
  122. ``payable`` on constructors is not enforced on Parity Substrate. Funds are needed
  123. for storage rent and there is a minimum deposit needed for the contract. As a result,
  124. constructors always receive value on Parity Substrate.
  125. Overriding function selector
  126. ____________________________
  127. When a function is called, the function selector and the arguments are serialized
  128. (also known as abi encoded) and passed to the program. The function selector is
  129. what the runtime program uses to determine what function was called. On Substrate, the
  130. function selector is generated using a deterministic hash value of the function
  131. name and the arguments types. On Solana, the selector is known as discriminator.
  132. The selector value can be overriden with the annotation
  133. ``@selector([0xde, 0xad, 0xbe, 0xa1])``.
  134. .. include:: ../examples/substrate/function_selector_override.sol
  135. :code: solidity
  136. The given example only works for Substrate, whose selectors are four bytes wide. On Solana, they are eight bytes wide.
  137. Only ``public`` and ``external`` functions have a selector, and can have their
  138. selector overriden. On Substrate, constructors have selectors too, so they
  139. can also have their selector overriden. If a function overrides another one in a
  140. base contract, then the selector of both must match.
  141. .. warning::
  142. On Solana, changing the selector may result in a mismatch between
  143. the contract metadata and the actual contract code, because the metadata does
  144. not explicitly store the selector.
  145. Use this feature carefully, as it may either break a contract or cause
  146. undefined behavior.
  147. Function overloading
  148. ____________________
  149. Multiple functions with the same name can be declared, as long as the arguments are
  150. different in at least one of two ways:
  151. - The number of arguments must be different
  152. - The type of at least one of the arguments is different
  153. A function cannot be overloaded by changing the return types or number of returned
  154. values. Here is an example of an overloaded function:
  155. .. include:: ../examples/function_overloading.sol
  156. :code: solidity
  157. In the function foo, abs() is called with an ``int64`` so the second implementation
  158. of the function abs() is called.
  159. Both Substrate and Solana runtime require unique function names, so
  160. overloaded function names will be mangled in the ABI or the IDL.
  161. The function name will be concatenated with all of its argument types, separated by underscores, using the
  162. following rules:
  163. - Struct types are represented by their field types (preceded by an extra underscore).
  164. - Enum types are represented as their underlying ``uint8`` type.
  165. - Array types are recognizable by having ``Array`` appended.
  166. - Fixed size arrays will additionally have their length appended as well.
  167. The following example illustrates some overloaded functions and their mangled name:
  168. .. include:: ../examples/function_name_mangling.sol
  169. :code: solidity
  170. Function Modifiers
  171. __________________
  172. Function modifiers are used to check pre-conditions or post-conditions for a function call. First a
  173. new modifier must be declared which looks much like a function, but uses the ``modifier``
  174. keyword rather than ``function``.
  175. .. include:: ../examples/substrate/function_modifier.sol
  176. :code: solidity
  177. The function `foo` can only be run by the owner of the contract, else the ``require()`` in its
  178. modifier will fail. The special symbol ``_;`` will be replaced by body of the function. In fact,
  179. if you specify ``_;`` twice, the function will execute twice, which might not be a good idea.
  180. On Solana, ``msg.sender`` does not exist, so the usual way to implement a similar test is using
  181. an `authority` accounts rather than an owner account.
  182. .. include:: ../examples/solana/use_authority.sol
  183. :code: solidity
  184. A modifier cannot have visibility (e.g. ``public``) or mutability (e.g. ``view``) specified,
  185. since a modifier is never externally callable. Modifiers can only be used by attaching them
  186. to functions.
  187. A modifier can have arguments, just like regular functions. Here if the price is less
  188. than 50, `foo()` itself will never be executed, and execution will return to the caller with
  189. nothing done since ``_;`` is not reached in the modifier and as result foo() is never
  190. executed.
  191. .. include:: ../examples/function_modifier_arguments.sol
  192. :code: solidity
  193. Multiple modifiers can be applied to single function. The modifiers are executed in the
  194. order of the modifiers specified on the function declaration. Execution will continue to the next modifier
  195. when the ``_;`` is reached. In
  196. this example, the `only_owner` modifier is run first, and if that reaches ``_;``, then
  197. `check_price` is executed. The body of function `foo()` is only reached once `check_price()`
  198. reaches ``_;``.
  199. .. include:: ../examples/substrate/function_multiple_modifiers.sol
  200. :code: solidity
  201. Modifiers can be inherited or declared ``virtual`` in a base contract and then overriden, exactly like
  202. functions can be.
  203. .. include:: ../examples/substrate/function_override_modifiers.sol
  204. :code: solidity
  205. Calling an external function using ``call()``
  206. _____________________________________________
  207. If you call a function on a contract, then the function selector and any arguments
  208. are ABI encoded for you, and any return values are decoded. Sometimes it is useful
  209. to call a function without abi encoding the arguments.
  210. You can call a contract directly by using the ``call()`` method on the address type.
  211. This takes a single argument, which should be the ABI encoded arguments. The return
  212. values are a ``boolean`` which indicates success if true, and the ABI encoded
  213. return value in ``bytes``.
  214. .. include:: ../examples/function_call.sol
  215. :code: solidity
  216. Any value or gas limit can be specified for the external call. Note that no check is done to see
  217. if the called function is ``payable``, since the compiler does not know what function you are
  218. calling.
  219. .. code-block:: solidity
  220. function test(address foo, bytes rawcalldata) public {
  221. (bool success, bytes rawresult) = foo.call{value: 102, gas: 1000}(rawcalldata);
  222. }
  223. .. _fallback_receive:
  224. Calling an external function using ``delegatecall``
  225. ___________________________________________________
  226. External functions can also be called using ``delegatecall``.
  227. The difference to a regular ``call`` is that ``delegatecall`` executes the callee code in the context of the caller:
  228. * The callee will read from and write to the `caller` storage.
  229. * ``value`` can't be specified for ``delegatecall``; instead it will always stay the same in the callee.
  230. * ``msg.sender`` does not change; it stays the same as in the callee.
  231. Refer to the `contracts pallet <https://docs.rs/pallet-contracts/latest/pallet_contracts/api_doc/trait.Version0.html#tymethod.delegate_call>`_
  232. and `Ethereum Solidity <https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#delegatecall-and-libraries>`_
  233. documentations for more information.
  234. ``delegatecall`` is commonly used to implement re-usable libraries and
  235. `upgradeable contracts <https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable>`_.
  236. .. code-block:: solidity
  237. function delegate(
  238. address callee,
  239. bytes input
  240. ) public returns(bytes result) {
  241. (bool ok, result) = callee.delegatecall(input);
  242. require(ok);
  243. }
  244. .. note::
  245. ``delegatecall`` is not available on Solana.
  246. .. note::
  247. On Substrate, specifying ``gas`` won't have any effect on ``delegatecall``.
  248. fallback() and receive() function
  249. _________________________________
  250. When a function is called externally, either via an transaction or when one contract
  251. call a function on another contract, the correct function is dispatched based on the
  252. function selector in the raw encoded ABI call data. If there is no match, the call
  253. reverts, unless there is a ``fallback()`` or ``receive()`` function defined.
  254. If the call comes with value, then ``receive()`` is executed, otherwise ``fallback()``
  255. is executed. This made clear in the declarations; ``receive()`` must be declared
  256. ``payable``, and ``fallback()`` must not be declared ``payable``. If a call is made
  257. with value and no ``receive()`` function is defined, then the call reverts, likewise if
  258. call is made without value and no ``fallback()`` is defined, then the call also reverts.
  259. Both functions must be declared ``external``.
  260. .. include:: ../examples/substrate/function_fallback_and_receive.sol
  261. :code: solidity
  262. .. note::
  263. On Solana, there is no mechanism to have some code executed if an account
  264. gets credited. So, `receive()` functions are not supported.