mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
275 lines
11 KiB
ReStructuredText
275 lines
11 KiB
ReStructuredText
********************************
|
|
Layout of a Solidity Source File
|
|
********************************
|
|
|
|
Source files can contain an arbitrary number of
|
|
:ref:`contract definitions<contract_structure>`, import_ directives,
|
|
:ref:`pragma directives<pragma>` and
|
|
:ref:`struct<structs>`, :ref:`enum<enums>`, :ref:`function<functions>`, :ref:`error<errors>`
|
|
and :ref:`constant variable<constants>` definitions.
|
|
|
|
.. index:: ! license, spdx
|
|
|
|
SPDX License Identifier
|
|
=======================
|
|
|
|
Trust in smart contract can be better established if their source code
|
|
is available. Since making source code available always touches on legal problems
|
|
with regards to copyright, the Solidity compiler encourages the use
|
|
of machine-readable `SPDX license identifiers <https://spdx.org>`_.
|
|
Every source file should start with a comment indicating its license:
|
|
|
|
``// SPDX-License-Identifier: MIT``
|
|
|
|
The compiler does not validate that the license is part of the
|
|
`list allowed by SPDX <https://spdx.org/licenses/>`_, but
|
|
it does include the supplied string in the :ref:`bytecode metadata <metadata>`.
|
|
|
|
If you do not want to specify a license or if the source code is
|
|
not open-source, please use the special value ``UNLICENSED``.
|
|
|
|
Supplying this comment of course does not free you from other
|
|
obligations related to licensing like having to mention
|
|
a specific license header in each source file or the
|
|
original copyright holder.
|
|
|
|
The comment is recognized by the compiler anywhere in the file at the
|
|
file level, but it is recommended to put it at the top of the file.
|
|
|
|
More information about how to use SPDX license identifiers
|
|
can be found at the `SPDX website <https://spdx.org/ids-how>`_.
|
|
|
|
|
|
.. index:: ! pragma
|
|
|
|
.. _pragma:
|
|
|
|
Pragmas
|
|
=======
|
|
|
|
The ``pragma`` keyword is used to enable certain compiler features
|
|
or checks. A pragma directive is always local to a source file, so
|
|
you have to add the pragma to all your files if you want to enable it
|
|
in your whole project. If you :ref:`import<import>` another file, the pragma
|
|
from that file does *not* automatically apply to the importing file.
|
|
|
|
.. index:: ! pragma, version
|
|
|
|
.. _version_pragma:
|
|
|
|
Version Pragma
|
|
--------------
|
|
|
|
Source files can (and should) be annotated with a version pragma to reject
|
|
compilation with future compiler versions that might introduce incompatible
|
|
changes. We try to keep these to an absolute minimum and
|
|
introduce them in a way that changes in semantics also require changes
|
|
in the syntax, but this is not always possible. Because of this, it is always
|
|
a good idea to read through the changelog at least for releases that contain
|
|
breaking changes. These releases always have versions of the form
|
|
``0.x.0`` or ``x.0.0``.
|
|
|
|
The version pragma is used as follows: ``pragma solidity ^0.5.2;``
|
|
|
|
A source file with the line above does not compile with a compiler earlier than version 0.5.2,
|
|
and it also does not work on a compiler starting from version 0.6.0 (this
|
|
second condition is added by using ``^``). Because
|
|
there will be no breaking changes until version ``0.6.0``, you can
|
|
be sure that your code compiles the way you intended. The exact version of the
|
|
compiler is not fixed, so that bugfix releases are still possible.
|
|
|
|
It is possible to specify more complex rules for the compiler version,
|
|
these follow the same syntax used by `npm <https://docs.npmjs.com/cli/v6/using-npm/semver>`_.
|
|
|
|
.. note::
|
|
Using the version pragma *does not* change the version of the compiler.
|
|
It also *does not* enable or disable features of the compiler. It just
|
|
instructs the compiler to check whether its version matches the one
|
|
required by the pragma. If it does not match, the compiler issues
|
|
an error.
|
|
|
|
ABI Coder Pragma
|
|
----------------
|
|
|
|
By using ``pragma abicoder v1`` or ``pragma abicoder v2`` you can
|
|
select between the two implementations of the ABI encoder and decoder.
|
|
|
|
The new ABI coder (v2) is able to encode and decode arbitrarily nested
|
|
arrays and structs. It might produce less optimal code and has not
|
|
received as much testing as the old encoder, but is considered
|
|
non-experimental as of Solidity 0.6.0. You still have to explicitly
|
|
activate it using ``pragma abicoder v2;``. Since it will be
|
|
activated by default starting from Solidity 0.8.0, there is the option to select
|
|
the old coder using ``pragma abicoder v1;``.
|
|
|
|
The set of types supported by the new encoder is a strict superset of
|
|
the ones supported by the old one. Contracts that use it can interact with ones
|
|
that do not without limitations. The reverse is possible only as long as the
|
|
non-``abicoder v2`` contract does not try to make calls that would require
|
|
decoding types only supported by the new encoder. The compiler can detect this
|
|
and will issue an error. Simply enabling ``abicoder v2`` for your contract is
|
|
enough to make the error go away.
|
|
|
|
.. note::
|
|
This pragma applies to all the code defined in the file where it is activated,
|
|
regardless of where that code ends up eventually. This means that a contract
|
|
whose source file is selected to compile with ABI coder v1
|
|
can still contain code that uses the new encoder
|
|
by inheriting it from another contract. This is allowed if the new types are only
|
|
used internally and not in external function signatures.
|
|
|
|
.. note::
|
|
Up to Solidity 0.7.4, it was possible to select the ABI coder v2
|
|
by using ``pragma experimental ABIEncoderV2``, but it was not possible
|
|
to explicitly select coder v1 because it was the default.
|
|
|
|
.. index:: ! pragma, experimental
|
|
|
|
.. _experimental_pragma:
|
|
|
|
Experimental Pragma
|
|
-------------------
|
|
|
|
The second pragma is the experimental pragma. It can be used to enable
|
|
features of the compiler or language that are not yet enabled by default.
|
|
The following experimental pragmas are currently supported:
|
|
|
|
|
|
ABIEncoderV2
|
|
~~~~~~~~~~~~
|
|
|
|
Because the ABI coder v2 is not considered experimental anymore,
|
|
it can be selected via ``pragma abicoder v2`` (please see above)
|
|
since Solidity 0.7.4.
|
|
|
|
.. _smt_checker:
|
|
|
|
SMTChecker
|
|
~~~~~~~~~~
|
|
|
|
This component has to be enabled when the Solidity compiler is built
|
|
and therefore it is not available in all Solidity binaries.
|
|
The :ref:`build instructions<smt_solvers_build>` explain how to activate this option.
|
|
It is activated for the Ubuntu PPA releases in most versions,
|
|
but not for the Docker images, Windows binaries or the
|
|
statically-built Linux binaries. It can be activated for solc-js via the
|
|
`smtCallback <https://github.com/ethereum/solc-js#example-usage-with-smtsolver-callback>`_ if you have an SMT solver
|
|
installed locally and run solc-js via node (not via the browser).
|
|
|
|
If you use ``pragma experimental SMTChecker;``, then you get additional
|
|
:ref:`safety warnings<formal_verification>` which are obtained by querying an
|
|
SMT solver.
|
|
The component does not yet support all features of the Solidity language and
|
|
likely outputs many warnings. In case it reports unsupported features, the
|
|
analysis may not be fully sound.
|
|
|
|
.. index:: source file, ! import, module, source unit
|
|
|
|
.. _import:
|
|
|
|
Importing other Source Files
|
|
============================
|
|
|
|
Syntax and Semantics
|
|
--------------------
|
|
|
|
Solidity supports import statements to help modularise your code that
|
|
are similar to those available in JavaScript
|
|
(from ES6 on). However, Solidity does not support the concept of
|
|
a `default export <https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export#Description>`_.
|
|
|
|
At a global level, you can use import statements of the following form:
|
|
|
|
.. code-block:: solidity
|
|
|
|
import "filename";
|
|
|
|
The ``filename`` part is called an *import path*.
|
|
This statement imports all global symbols from "filename" (and symbols imported there) into the
|
|
current global scope (different than in ES6 but backwards-compatible for Solidity).
|
|
This form is not recommended for use, because it unpredictably pollutes the namespace.
|
|
If you add new top-level items inside "filename", they automatically
|
|
appear in all files that import like this from "filename". It is better to import specific
|
|
symbols explicitly.
|
|
|
|
The following example creates a new global symbol ``symbolName`` whose members are all
|
|
the global symbols from ``"filename"``:
|
|
|
|
.. code-block:: solidity
|
|
|
|
import * as symbolName from "filename";
|
|
|
|
which results in all global symbols being available in the format ``symbolName.symbol``.
|
|
|
|
A variant of this syntax that is not part of ES6, but possibly useful is:
|
|
|
|
.. code-block:: solidity
|
|
|
|
import "filename" as symbolName;
|
|
|
|
which is equivalent to ``import * as symbolName from "filename";``.
|
|
|
|
If there is a naming collision, you can rename symbols while importing. For example,
|
|
the code below creates new global symbols ``alias`` and ``symbol2`` which reference
|
|
``symbol1`` and ``symbol2`` from inside ``"filename"``, respectively.
|
|
|
|
.. code-block:: solidity
|
|
|
|
import {symbol1 as alias, symbol2} from "filename";
|
|
|
|
.. index:: virtual filesystem, source unit name, import; path, filesystem path, import callback, Remix IDE
|
|
|
|
Import Paths
|
|
------------
|
|
|
|
In order to be able to support reproducible builds on all platforms, the Solidity compiler has to
|
|
abstract away the details of the filesystem where source files are stored.
|
|
For this reason import paths do not refer directly to files in the host filesystem.
|
|
Instead the compiler maintains an internal database (*virtual filesystem* or *VFS* for short) where
|
|
each source unit is assigned a unique *source unit name* which is an opaque and unstructured identifier.
|
|
The import path specified in an import statement is translated into a source unit name and used to
|
|
find the corresponding source unit in this database.
|
|
|
|
Using the :ref:`Standard JSON <compiler-api>` API it is possible to directly provide the names and
|
|
content of all the source files as a part of the compiler input.
|
|
In this case source unit names are truly arbitrary.
|
|
If, however, you want the compiler to automatically find and load source code into the VFS, your
|
|
source unit names need to be structured in a way that makes it possible for an :ref:`import callback
|
|
<import-callback>` to locate them.
|
|
When using the command-line compiler the default import callback supports only loading source code
|
|
from the host filesystem, which means that your source unit names must be paths.
|
|
Some environments provide custom callbacks that are more versatile.
|
|
For example the `Remix IDE <https://remix.ethereum.org/>`_ provides one that
|
|
lets you `import files from HTTP, IPFS and Swarm URLs or refer directly to packages in NPM registry
|
|
<https://remix-ide.readthedocs.io/en/latest/import.html>`_.
|
|
|
|
For a complete description of the virtual filesystem and the path resolution logic used by the
|
|
compiler see :ref:`Path Resolution <path-resolution>`.
|
|
|
|
.. index:: ! comment, natspec
|
|
|
|
Comments
|
|
========
|
|
|
|
Single-line comments (``//``) and multi-line comments (``/*...*/``) are possible.
|
|
|
|
.. code-block:: solidity
|
|
|
|
// This is a single-line comment.
|
|
|
|
/*
|
|
This is a
|
|
multi-line comment.
|
|
*/
|
|
|
|
.. note::
|
|
A single-line comment is terminated by any unicode line terminator
|
|
(LF, VF, FF, CR, NEL, LS or PS) in UTF-8 encoding. The terminator is still part of
|
|
the source code after the comment, so if it is not an ASCII symbol
|
|
(these are NEL, LS and PS), it will lead to a parser error.
|
|
|
|
Additionally, there is another type of comment called a NatSpec comment,
|
|
which is detailed in the :ref:`style guide<style_guide_natspec>`. They are written with a
|
|
triple slash (``///``) or a double asterisk block (``/** ... */``) and
|
|
they should be used directly above function declarations or statements.
|