mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5756 from ethereum/docs-split-libraries
[DOCS] Split libraries into new doc
This commit is contained in:
commit
28c25efc80
@ -536,235 +536,6 @@ converted to ``uint8``.
|
||||
.. include:: contracts/abstract-contracts.rst
|
||||
.. include:: contracts/interfaces.rst
|
||||
|
||||
.. 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/libraries.rst
|
||||
|
||||
.. include:: contracts/using-for.rst
|
230
docs/contracts/libraries.rst
Normal file
230
docs/contracts/libraries.rst
Normal file
@ -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.
|
Loading…
Reference in New Issue
Block a user