mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
cfa1198892
[DOCS] Split using for into new file
806 lines
28 KiB
ReStructuredText
806 lines
28 KiB
ReStructuredText
.. index:: ! contract
|
|
|
|
.. _contracts:
|
|
|
|
##########
|
|
Contracts
|
|
##########
|
|
|
|
Contracts in Solidity are similar to classes in object-oriented languages. They
|
|
contain persistent data in state variables and functions that can modify these
|
|
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.
|
|
|
|
.. include:: contracts/creating-contracts.rst
|
|
|
|
.. include:: contracts/visibility-and-getters.rst
|
|
|
|
.. 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/constant-state-variables.rst
|
|
|
|
.. index:: ! functions
|
|
|
|
.. _functions:
|
|
|
|
*********
|
|
Functions
|
|
*********
|
|
|
|
.. _function-parameters-return-variables:
|
|
|
|
Function Parameters and Return Variables
|
|
========================================
|
|
|
|
As in JavaScript, functions may take parameters as input. Unlike in JavaScript
|
|
and C, functions may also return an arbitrary number of values as output.
|
|
|
|
Function Parameters
|
|
-------------------
|
|
|
|
Function parameters are declared the same way as variables, and the name of
|
|
unused parameters can be omitted.
|
|
|
|
For example, if you want your contract to accept one kind of external call
|
|
with two integers, you would use something like::
|
|
|
|
pragma solidity >=0.4.16 <0.6.0;
|
|
|
|
contract Simple {
|
|
uint sum;
|
|
function taker(uint _a, uint _b) public {
|
|
sum = _a + _b;
|
|
}
|
|
}
|
|
|
|
Function parameters can be used as any other local variable and they can also be assigned to.
|
|
|
|
.. note::
|
|
|
|
An :ref:`external function<external-function-calls>` cannot accept a
|
|
multi-dimensional array as an input
|
|
parameter. This functionality is possible if you enable the new
|
|
experimental ``ABIEncoderV2`` feature by adding ``pragma experimental ABIEncoderV2;`` to your source file.
|
|
|
|
An :ref:`internal function<external-function-calls>` can accept a
|
|
multi-dimensional array without enabling the feature.
|
|
|
|
.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct
|
|
|
|
Return Variables
|
|
----------------
|
|
|
|
Function return variables are declared with the same syntax after the
|
|
``returns`` keyword.
|
|
|
|
For example, suppose you want to return two results: the sum and the product of
|
|
two integers passed as function parameters, then you use something like::
|
|
|
|
pragma solidity >=0.4.16 <0.6.0;
|
|
|
|
contract Simple {
|
|
function arithmetic(uint _a, uint _b)
|
|
public
|
|
pure
|
|
returns (uint o_sum, uint o_product)
|
|
{
|
|
o_sum = _a + _b;
|
|
o_product = _a * _b;
|
|
}
|
|
}
|
|
|
|
The names of return variables can be omitted.
|
|
Return variables can be used as any other local variable and they
|
|
are initialized with their :ref:`default value <default-value>` and have that value unless explicitly set.
|
|
|
|
You can either explicitly assign to return variables and
|
|
then leave the function using ``return;``,
|
|
or you can provide return values
|
|
(either a single or :ref:`multiple ones<multi-return>`) directly with the ``return``
|
|
statement::
|
|
|
|
pragma solidity >=0.4.16 <0.6.0;
|
|
|
|
contract Simple {
|
|
function arithmetic(uint _a, uint _b)
|
|
public
|
|
pure
|
|
returns (uint o_sum, uint o_product)
|
|
{
|
|
return (_a + _b, _a * _b);
|
|
}
|
|
}
|
|
|
|
This form is equivalent to first assigning values to the
|
|
return variables and then using ``return;`` to leave the function.
|
|
|
|
.. note::
|
|
You cannot return some types from non-internal functions, notably
|
|
multi-dimensional dynamic arrays and structs. If you enable the
|
|
new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental
|
|
ABIEncoderV2;`` to your source file then more types are available, but
|
|
``mapping`` types are still limited to inside a single contract and you
|
|
cannot transfer them.
|
|
|
|
.. _multi-return:
|
|
|
|
Returning Multiple Values
|
|
-------------------------
|
|
|
|
When a function has multiple return types, the statement ``return (v0, v1, ..., vn)`` can be used to return multiple values.
|
|
The number of components must be the same as the number of return types.
|
|
|
|
.. index:: ! view function, function;view
|
|
|
|
.. _view-functions:
|
|
|
|
View Functions
|
|
==============
|
|
|
|
Functions can be declared ``view`` in which case they promise not to modify the state.
|
|
|
|
.. note::
|
|
If the compiler's EVM target is Byzantium or newer (default) the opcode
|
|
``STATICCALL`` is used for ``view`` functions which enforces the state
|
|
to stay unmodified as part of the EVM execution. For library ``view`` functions
|
|
``DELEGATECALL`` is used, because there is no combined ``DELEGATECALL`` and ``STATICCALL``.
|
|
This means library ``view`` functions do not have run-time checks that prevent state
|
|
modifications. This should not impact security negatively because library code is
|
|
usually known at compile-time and the static checker performs compile-time checks.
|
|
|
|
The following statements are considered modifying the state:
|
|
|
|
#. Writing to state variables.
|
|
#. :ref:`Emitting events <events>`.
|
|
#. :ref:`Creating other contracts <creating-contracts>`.
|
|
#. Using ``selfdestruct``.
|
|
#. Sending Ether via calls.
|
|
#. Calling any function not marked ``view`` or ``pure``.
|
|
#. Using low-level calls.
|
|
#. Using inline assembly that contains certain opcodes.
|
|
|
|
::
|
|
|
|
pragma solidity ^0.5.0;
|
|
|
|
contract C {
|
|
function f(uint a, uint b) public view returns (uint) {
|
|
return a * (b + 42) + now;
|
|
}
|
|
}
|
|
|
|
.. note::
|
|
``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0.
|
|
|
|
.. note::
|
|
Getter methods are automatically marked ``view``.
|
|
|
|
.. note::
|
|
Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode
|
|
for ``view`` functions.
|
|
This enabled state modifications in ``view`` functions through the use of
|
|
invalid explicit type conversions.
|
|
By using ``STATICCALL`` for ``view`` functions, modifications to the
|
|
state are prevented on the level of the EVM.
|
|
|
|
.. index:: ! pure function, function;pure
|
|
|
|
.. _pure-functions:
|
|
|
|
Pure Functions
|
|
==============
|
|
|
|
Functions can be declared ``pure`` in which case they promise not to read from or modify the state.
|
|
|
|
.. note::
|
|
If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used,
|
|
which does not guarantee that the state is not read, but at least that it is not modified.
|
|
|
|
In addition to the list of state modifying statements explained above, the following are considered reading from the state:
|
|
|
|
#. Reading from state variables.
|
|
#. Accessing ``address(this).balance`` or ``<address>.balance``.
|
|
#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``).
|
|
#. Calling any function not marked ``pure``.
|
|
#. Using inline assembly that contains certain opcodes.
|
|
|
|
::
|
|
|
|
pragma solidity ^0.5.0;
|
|
|
|
contract C {
|
|
function f(uint a, uint b) public pure returns (uint) {
|
|
return a * (b + 42);
|
|
}
|
|
}
|
|
|
|
Pure functions are able to use the `revert()` and `require()` functions to revert
|
|
potential state changes when an :ref:`error occurs <assert-and-require>`.
|
|
|
|
Reverting a state change is not considered a "state modification", as only changes to the
|
|
state made previously in code that did not have the ``view`` or ``pure`` restriction
|
|
are reverted and that code has the option to catch the ``revert`` and not pass it on.
|
|
|
|
This behaviour is also in line with the ``STATICCALL`` opcode.
|
|
|
|
.. warning::
|
|
It is not possible to prevent functions from reading the state at the level
|
|
of the EVM, it is only possible to prevent them from writing to the state
|
|
(i.e. only ``view`` can be enforced at the EVM level, ``pure`` can not).
|
|
|
|
.. note::
|
|
Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode
|
|
for ``pure`` functions.
|
|
This enabled state modifications in ``pure`` functions through the use of
|
|
invalid explicit type conversions.
|
|
By using ``STATICCALL`` for ``pure`` functions, modifications to the
|
|
state are prevented on the level of the EVM.
|
|
|
|
.. note::
|
|
Prior to version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state.
|
|
It is a compile-time type check, which can be circumvented doing invalid explicit conversions
|
|
between contract types, because the compiler can verify that the type of the contract does
|
|
not do state-changing operations, but it cannot check that the contract that will be called
|
|
at runtime is actually of that type.
|
|
|
|
.. index:: ! fallback function, function;fallback
|
|
|
|
.. _fallback-function:
|
|
|
|
Fallback Function
|
|
=================
|
|
|
|
A contract can have exactly one unnamed function. This function cannot have
|
|
arguments, cannot return anything and has to have ``external`` visibility.
|
|
It is executed on a call to the contract if none of the other
|
|
functions match the given function identifier (or if no data was supplied at
|
|
all).
|
|
|
|
Furthermore, this function is executed whenever the contract receives plain
|
|
Ether (without data). Additionally, in order to receive Ether, the fallback function
|
|
must be marked ``payable``. If no such function exists, the contract cannot receive
|
|
Ether through regular transactions.
|
|
|
|
In the worst case, the fallback function can only rely on 2300 gas being
|
|
available (for example when `send` or `transfer` is used), leaving little
|
|
room to perform other operations except basic logging. The following operations
|
|
will consume more gas than the 2300 gas stipend:
|
|
|
|
- Writing to storage
|
|
- Creating a contract
|
|
- Calling an external function which consumes a large amount of gas
|
|
- Sending Ether
|
|
|
|
Like any function, the fallback function can execute complex operations as long as there is enough gas passed on to it.
|
|
|
|
.. note::
|
|
Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve
|
|
any payload supplied with the call.
|
|
|
|
.. warning::
|
|
The fallback function is also executed if the caller meant to call
|
|
a function that is not available. If you want to implement the fallback
|
|
function only to receive ether, you should add a check
|
|
like ``require(msg.data.length == 0)`` to prevent invalid calls.
|
|
|
|
.. warning::
|
|
Contracts that receive Ether directly (without a function call, i.e. using ``send`` or ``transfer``)
|
|
but do not define a fallback function
|
|
throw an exception, sending back the Ether (this was different
|
|
before Solidity v0.4.0). So if you want your contract to receive Ether,
|
|
you have to implement a payable fallback function.
|
|
|
|
.. warning::
|
|
A contract without a payable fallback function can receive Ether as a recipient of a `coinbase transaction` (aka `miner block reward`)
|
|
or as a destination of a ``selfdestruct``.
|
|
|
|
A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of the EVM and Solidity cannot work around it.
|
|
|
|
It also means that ``address(this).balance`` can be higher than the sum of some manual accounting implemented in a contract (i.e. having a counter updated in the fallback function).
|
|
|
|
::
|
|
|
|
pragma solidity ^0.5.0;
|
|
|
|
contract Test {
|
|
// This function is called for all messages sent to
|
|
// this contract (there is no other function).
|
|
// Sending Ether to this contract will cause an exception,
|
|
// because the fallback function does not have the `payable`
|
|
// modifier.
|
|
function() external { x = 1; }
|
|
uint x;
|
|
}
|
|
|
|
|
|
// This contract keeps all Ether sent to it with no way
|
|
// to get it back.
|
|
contract Sink {
|
|
function() external payable { }
|
|
}
|
|
|
|
contract Caller {
|
|
function callTest(Test test) public returns (bool) {
|
|
(bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
|
|
require(success);
|
|
// results in test.x becoming == 1.
|
|
|
|
// address(test) will not allow to call ``send`` directly, since ``test`` has no payable
|
|
// fallback function. It has to be converted to the ``address payable`` type via an
|
|
// intermediate conversion to ``uint160`` to even allow calling ``send`` on it.
|
|
address payable testPayable = address(uint160(address(test)));
|
|
|
|
// If someone sends ether to that contract,
|
|
// the transfer will fail, i.e. this returns false here.
|
|
return testPayable.send(2 ether);
|
|
}
|
|
}
|
|
|
|
.. index:: ! overload
|
|
|
|
.. _overload-function:
|
|
|
|
Function Overloading
|
|
====================
|
|
|
|
A contract can have multiple functions of the same name but with different parameter
|
|
types.
|
|
This process is called "overloading" and also applies to inherited functions.
|
|
The following example shows overloading of the function
|
|
``f`` in the scope of contract ``A``.
|
|
|
|
::
|
|
|
|
pragma solidity >=0.4.16 <0.6.0;
|
|
|
|
contract A {
|
|
function f(uint _in) public pure returns (uint out) {
|
|
out = _in;
|
|
}
|
|
|
|
function f(uint _in, bool _really) public pure returns (uint out) {
|
|
if (_really)
|
|
out = _in;
|
|
}
|
|
}
|
|
|
|
Overloaded functions are also present in the external interface. It is an error if two
|
|
externally visible functions differ by their Solidity types but not by their external types.
|
|
|
|
::
|
|
|
|
pragma solidity >=0.4.16 <0.6.0;
|
|
|
|
// This will not compile
|
|
contract A {
|
|
function f(B _in) public pure returns (B out) {
|
|
out = _in;
|
|
}
|
|
|
|
function f(address _in) public pure returns (address out) {
|
|
out = _in;
|
|
}
|
|
}
|
|
|
|
contract B {
|
|
}
|
|
|
|
|
|
Both ``f`` function overloads above end up accepting the address type for the ABI although
|
|
they are considered different inside Solidity.
|
|
|
|
Overload resolution and Argument matching
|
|
-----------------------------------------
|
|
|
|
Overloaded functions are selected by matching the function declarations in the current scope
|
|
to the arguments supplied in the function call. Functions are selected as overload candidates
|
|
if all arguments can be implicitly converted to the expected types. If there is not exactly one
|
|
candidate, resolution fails.
|
|
|
|
.. note::
|
|
Return parameters are not taken into account for overload resolution.
|
|
|
|
::
|
|
|
|
pragma solidity >=0.4.16 <0.6.0;
|
|
|
|
contract A {
|
|
function f(uint8 _in) public pure returns (uint8 out) {
|
|
out = _in;
|
|
}
|
|
|
|
function f(uint256 _in) public pure returns (uint256 out) {
|
|
out = _in;
|
|
}
|
|
}
|
|
|
|
Calling ``f(50)`` would create a type error since ``50`` can be implicitly converted both to ``uint8``
|
|
and ``uint256`` types. On another hand ``f(256)`` would resolve to ``f(uint256)`` overload as ``256`` cannot be implicitly
|
|
converted to ``uint8``.
|
|
|
|
.. include:: contracts/events.rst
|
|
|
|
.. include:: contracts/inheritance.rst
|
|
|
|
.. include:: contracts/abstract-contracts.rst
|
|
|
|
.. 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``.
|
|
|
|
.. 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.
|
|
|
|
.. include:: contracts/using-for.rst |