functions.rst 16 KB

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