Skip to content

Commit

Permalink
Adds documentation for Solidity source upgrader.
Browse files Browse the repository at this point in the history
  • Loading branch information
erak authored and chriseth committed Feb 5, 2020
1 parent 5de3379 commit f2701db
Show file tree
Hide file tree
Showing 22 changed files with 1,911 additions and 11 deletions.
7 changes: 7 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ defaults:
path: build/solc/solc
destination: solc

# compiled tool executable target
- artifacts_tools: &artifacts_tools
path: build/tools/solidity-upgrade
destination: solidity-upgrade

# compiled executable targets
- artifacts_executables: &artifacts_executables
root: build
Expand Down Expand Up @@ -324,6 +329,7 @@ jobs:
- checkout
- run: *run_build
- store_artifacts: *artifacts_solc
- store_artifacts: *artifacts_tools
- persist_to_workspace: *artifacts_executables

b_ubu_release: &build_ubuntu1904_release
Expand Down Expand Up @@ -455,6 +461,7 @@ jobs:
- /usr/local/Homebrew
- run: *run_build
- store_artifacts: *artifacts_solc
- store_artifacts: *artifacts_tools
- persist_to_workspace: *artifacts_build_dir

t_osx_soltest:
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ add_subdirectory(libevmasm)
add_subdirectory(libyul)
add_subdirectory(libsolidity)
add_subdirectory(libsolc)
add_subdirectory(tools)

if (NOT EMSCRIPTEN)
add_subdirectory(solc)
Expand Down
237 changes: 237 additions & 0 deletions docs/using-the-compiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -474,3 +474,240 @@ Error types
11. ``CompilerError``: Invalid use of the compiler stack - this should be reported as an issue.
12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue.
13. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible.


.. _compiler-tools:

Compiler tools
**************

solidity-upgrade
----------------

``solidity-upgrade`` can help you to semi-automatically upgrade your contracts
to breaking language changes. While it does not and cannot implement all
required changes for every breaking release, it still supports the ones, that
would need plenty of repetitive manual adjustments otherwise.

.. note::

``solidity-upgrade`` carries out a large part of the work, but your
contracts will most likely need further manual adjustments. We recommend
using a version control system for your files. This helps reviewing and
eventually rolling back the changes made.

.. warning::

``solidity-upgrade`` is not considered to be complete or free from bugs, so
please use with care.

How it works
~~~~~~~~~~~~

You can pass (a) Solidity source file(s) to ``solidity-upgrade [files]``. If
these make use of ``import`` statement which refer to files outside the
current source file's directory, you need to specify directories that
are allowed to read and import files from, by passing
``--allow-paths [directory]``. You can ignore missing files by passing
``--ignore-missing``.

``solidity-upgrade`` is based on ``libsolidity`` and can parse, compile and
analyse your source files, and might find applicable source upgrades in them.

Source upgrades are considered to be small textual changes to your source code.
They are applied to an in-memory representation of the source files
given. The corresponding source file is updated by default, but you can pass
``--dry-run`` to simulate to whole upgrade process without writing to any file.

The upgrade process itself has two phases. In the first phase source files are
parsed, and since it is not possible to upgrade source code on that level,
errors are collected and can be logged by passing ``--verbose``. No source
upgrades available at this point.

In the second phase, all sources are compiled and all activated upgrade analysis
modules are run alongside compilation. By default, all available modules are
activated. Please read the documentation on
:ref:`available modules <upgrade-modules>` for further details.


This can result in compilation errors that may
be fixed by source upgrades. If no errors occur, no source upgrades are being
reported and you're done.
If errors occur and some upgrade module reported a source upgrade, the first
reported one gets applied and compilation is triggered again for all given
source files. The previous step is repeated as long as source upgrades are
reported. If errors still occur, you can log them by passing ``--verbose``.
If no errors occur, your contracts are up to date and can be compiled with
the latest version of the compiler.

.. _upgrade-modules:

Available upgrade modules
~~~~~~~~~~~~~~~~~~~~~~~~~

+-----------------+---------+--------------------------------------------------+
| Module | Version | Description |
+=================+=========+==================================================+
| ``constructor`` | 0.5.0 | Constructors must now be defined using the |
| | | ``constructor`` keyword. |
+-----------------+---------+--------------------------------------------------+
| ``visibility`` | 0.5.0 | Explicit function visibility is now mandatory, |
| | | defaults to ``public``. |
+-----------------+---------+--------------------------------------------------+
| ``abstract`` | 0.6.0 | The keyword ``abstract`` has to be used if a |
| | | contract does not implement all its functions. |
+-----------------+---------+--------------------------------------------------+
| ``virtual`` | 0.6.0 | Functions without implementation outside an |
| | | interface have to be marked ``virtual``. |
+-----------------+---------+--------------------------------------------------+
| ``override`` | 0.6.0 | When overriding a function or modifier, the new |
| | | keyword ``override`` must be used. |
+-----------------+---------+--------------------------------------------------+

Please read :doc:`0.5.0 release notes <050-breaking-changes>` and
:doc:`0.6.0 release notes <060-breaking-changes>` for further details.

Synopsis
~~~~~~~~

.. code-block:: none
Usage: solidity-upgrade [options] contract.sol
Allowed options:
--help Show help message and exit.
--version Show version and exit.
--allow-paths path(s)
Allow a given path for imports. A list of paths can be
supplied by separating them with a comma.
--ignore-missing Ignore missing files.
--modules module(s) Only activate a specific upgrade module. A list of
modules can be supplied by separating them with a comma.
--dry-run Apply changes in-memory only and don't write to input
file.
--verbose Print logs, errors and changes. Shortens output of
upgrade patches.
--unsafe Accept *unsafe* changes.
Bug Reports / Feature requests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you found a bug or if you have a feature request, please
`file an issue <https://github.com/ethereum/solidity/issues/new/choose>`_ on Github.


Example
~~~~~~~

Assume you have the following contracts you want to update declared in ``Source.sol``:

.. code-block:: none
// This will not compile
pragma solidity >0.4.23;
contract Updateable {
function run() public view returns (bool);
function update() public;
}
contract Upgradable {
function run() public view returns (bool);
function upgrade();
}
contract Source is Updateable, Upgradable {
function Source() public {}
function run()
public
view
returns (bool) {}
function update() {}
function upgrade() {}
}
Required changes
^^^^^^^^^^^^^^^^

To bring the contracts up to date with the current Solidity version, the
following upgrade modules have to be executed: ``constructor``,
``visibility``, ``abstract``, ``override`` and ``virtual``. Please read the
documentation on :ref:`available modules <upgrade-modules>` for further details.

Running the upgrade
^^^^^^^^^^^^^^^^^^^

In this example, all modules needed to upgrade the contracts above,
are available and all of them are activated by default. Therefore you
do not need to specify the ``--modules`` option.

.. code-block:: none
$ solidity-upgrade Source.sol --dry-run
.. code-block:: none
Running analysis (and upgrade) on given source files.
..............
After upgrade:
Found 0 errors.
Found 0 upgrades.
The above performs a dry-ran upgrade on the given file and logs statistics after all.
In this case, the upgrade was successful and no further adjustments are needed.

Finally, you can run the upgrade and also write to the source file.

.. code-block:: none
$ solidity-upgrade Source.sol
.. code-block:: none
Running analysis (and upgrade) on given source files.
..............
After upgrade:
Found 0 errors.
Found 0 upgrades.
Review changes
^^^^^^^^^^^^^^

The command above applies all changes as shown below. Please review them carefully.

.. code-block:: none
pragma solidity >0.4.23;
abstract contract Updateable {
function run() public view virtual returns (bool);
function update() public virtual;
}
abstract contract Upgradable {
function run() public view virtual returns (bool);
function upgrade() public virtual;
}
contract Source is Updateable, Upgradable {
constructor() public {}
function run()
public
view
override(Updateable,Upgradable)
returns (bool) {}
function update() public override {}
function upgrade() public override {}
}
4 changes: 2 additions & 2 deletions libsolidity/analysis/OverrideChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,8 @@ vector<ContractDefinition const*> resolveDirectBaseContracts(ContractDefinition
Declaration const* baseDecl =
specifier->name().annotation().referencedDeclaration;
auto contract = dynamic_cast<ContractDefinition const*>(baseDecl);
solAssert(contract, "contract is null");
resolvedContracts.emplace_back(contract);
if (contract)
resolvedContracts.emplace_back(contract);
}

return resolvedContracts;
Expand Down
15 changes: 7 additions & 8 deletions libsolidity/analysis/OverrideChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class OverrideProxy
class OverrideChecker
{
public:
using OverrideProxyBySignatureMultiSet = std::multiset<OverrideProxy, OverrideProxy::CompareBySignature>;

/// @param _errorReporter provides the error logging functionality.
explicit OverrideChecker(langutil::ErrorReporter& _errorReporter):
Expand All @@ -137,12 +138,17 @@ class OverrideChecker

void check(ContractDefinition const& _contract);

private:
struct CompareByID
{
bool operator()(ContractDefinition const* _a, ContractDefinition const* _b) const;
};

/// Returns all functions of bases (including public state variables) that have not yet been overwritten.
/// May contain the same function multiple times when used with shared bases.
OverrideProxyBySignatureMultiSet const& inheritedFunctions(ContractDefinition const& _contract) const;
OverrideProxyBySignatureMultiSet const& inheritedModifiers(ContractDefinition const& _contract) const;

private:
void checkIllegalOverrides(ContractDefinition const& _contract);
/// Performs various checks related to @a _overriding overriding @a _super like
/// different return type, invalid visibility change, etc.
Expand Down Expand Up @@ -174,15 +180,8 @@ class OverrideChecker
/// Resolves an override list of UserDefinedTypeNames to a list of contracts.
std::set<ContractDefinition const*, CompareByID> resolveOverrideList(OverrideSpecifier const& _overrides) const;

using OverrideProxyBySignatureMultiSet = std::multiset<OverrideProxy, OverrideProxy::CompareBySignature>;

void checkOverrideList(OverrideProxy _item, OverrideProxyBySignatureMultiSet const& _inherited);

/// Returns all functions of bases (including public state variables) that have not yet been overwritten.
/// May contain the same function multiple times when used with shared bases.
OverrideProxyBySignatureMultiSet const& inheritedFunctions(ContractDefinition const& _contract) const;
OverrideProxyBySignatureMultiSet const& inheritedModifiers(ContractDefinition const& _contract) const;

langutil::ErrorReporter& m_errorReporter;

/// Cache for inheritedFunctions().
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ class FunctionDefinition: public CallableDeclaration, public StructurallyDocumen
{
return
CallableDeclaration::virtualSemantics() ||
annotation().contract->isInterface();
(annotation().contract && annotation().contract->isInterface());
}
private:
StateMutability m_stateMutability;
Expand Down
14 changes: 14 additions & 0 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
add_executable(solidity-upgrade
solidityUpgrade/main.cpp
solidityUpgrade/UpgradeChange.h
solidityUpgrade/UpgradeChange.cpp
solidityUpgrade/UpgradeSuite.h
solidityUpgrade/Upgrade050.cpp
solidityUpgrade/Upgrade060.cpp
solidityUpgrade/SourceTransform.h
solidityUpgrade/SourceUpgrade.cpp
)
target_link_libraries(solidity-upgrade PRIVATE solidity Boost::boost Boost::program_options Boost::system)

include(GNUInstallDirs)
install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}")
Loading

0 comments on commit f2701db

Please sign in to comment.